documentation/content/zh-cn/admin/scaling.md

11 KiB
Raw Blame History

title descriptions menu
伸缩你的服务器 为服务更多用户而优化。
docs
weight parent
100 admin

并发管理

Mastodon有三种进程

  • Web (Puma)
  • Streaming API
  • 后台进程 (Sidekiq)

Web (Puma)

web进程处理绝大多数应用的短HTTP请求。以下环境变量可以控制它

  • WEB_CONCURRENCY 控制worker进程数
  • MAX_THREADS 控制每进程的线程数

线程共享其父进程的内存。不同的线程被分配了专有内存虽然他们通过copy-on-write共享了一些内存。数量较多的线程会先消耗掉你的CPU数量较多的进程会先消耗掉你的内存。

这些数值会影响到可以同时处理多少HTTP请求。

在吞吐量方面,多进程比多线程要好。

Streaming API

streaming API处理长HTTP连接与WebSockets连接通过这些连接用户可以接受到实时更新。以下环境变量可以控制它

  • STREAMING_CLUSTER_NUM 控制worker进程数
  • STREAMING_API_BASE_URL 控制streaming API的base URL

一个进程可以处理相当数量的连接。 如果您愿意streaming API可以托管在其他子域上例如避免nginx代理连接开销。

后台进程 (Sidekiq)

Mastodon许多任务都分配给后台进程以确保HTTP请求快速响应并防止HTTP请求中止影响到这些任务的执行。Sidekiq是单个进程具有可配置的线程数。

线程数

虽然web进程数与web线程数影响Mastodon实例响应终端用户分配给后台进程的线程数影响嘟文从作者分发至其他人的速度电子邮件花多长时间发完等等。

Sidekiq的线程数并不受环境变量控制但是可通过命令行参数控制例如

bundle exec sidekiq -c 15

将启一个15线程的sidekiq进程。请注意每个线程都需要能够连接数据库这意味着数据库连接池应足够大以满足所有进程。数据库连接池的大小由DB_POOL环境变量控制,该变量必须至少与进程数同样大。

队列

Sidekiq根据任务的重要性使用不同队列这里的重要性是指如果队列不工作其对本地用户体验的冲击有多大。按重要性降序排列

队列 重要性
default 影响本地用户的所有任务
push 推送消息至其它服务器
mailers 分发电子邮件
pull 从其它服务器拉取信息
scheduler 完成计划任务,例如更新当下流行标签及清理日志

默认队列及其优先级存储于config/sidekiq.yml但可通过调用Sidekiq命令行覆盖例如

bundle exec sidekiq -q default

仅运行default队列。

Sidekiq处理队列的方式是它首先检查第一个队列中的任务如果没有则检查下一个队列。这意味着如果第一个队列已满其他队列将延后。

作为一种解决方案可以启动为不同队列启动不同的Sidekiq进程以确保真正的并列执行例如使用不同Sidekiq参数创建多个systemd服务。

请确保仅有一个scheduler队列!!

使用pgBouncer事务池

你为什么要用PgBouncer

如果开始耗尽可用的Postgres连接默认为100那PgBouncer可能是一个好方案。本文档将介绍Mastodon的一些常见陷阱及好的默认配置。

请注意你可以在管理界面的“PgHero”查看当前使用了多少Postgres连接。通常Mastodon使用Puma、Sidekiq、streaming API三者线程数总和的连接数。

安装PgBouncer

在Debian和Ubuntu

sudo apt install pgbouncer

配置PgBouncer

设置密码

首先如果你的Postgres中mastodon帐户没有设置密码的话,你需要设置一个密码。 First off, if your mastodon user in PostgreSQL is set up without a password, you will need to set a password.

下面是如何重置密码:

psql -p 5432 -U mastodon mastodon_production -w

之后很显然使用一个与单词“password”不同的密码

ALTER USER mastodon WITH PASSWORD 'password';

然后输入 \q 退出。

配置userlist.txt

编辑 /etc/pgbouncer/userlist.txt

只要稍后你在 pgbouncer.ini 中指定一个用户名/密码userlist.txt文件中的值不必与真实PostgreSQL用户相同。你可以随意设定用户名和密码但是为方便起来你可以重用“真实”的凭证。添加mastodon帐户至userlist.txt

"mastodon" "md5d75bb2be2d7086c6148944261a00f605"

这里我们使用md5格式这里的md5密码就是字符串密码 + 用户名的md5值附加上md5。例如:为了获得用户名为mastodon密码为password的散列值,你可以这样做:

# ubuntu, debian, etc.
echo -n "passwordmastodon" | md5sum
# macOS, openBSD, etc.
md5 -s "passwordmastodon"

然后将md5添加至开头。

你也可以创建一个pgbouncer管理帐户以登入查看PgBouncer管理数据库。下面是一个userlist.txt文件的例子:

"mastodon" "md5d75bb2be2d7086c6148944261a00f605"
"pgbouncer" "md5a45753afaca0db833a6f7c7b2864b9d9"

以上两个帐户密码者是password

配置 pgbouncer.ini

编辑 /etc/pgbouncer/pgbouncer.ini

[databases]行下列出你想连接的Postgres数据库。这里PgBouncer将使用同样的用户名/密码和数据库名称连接下层Postgres数据库

[databases]
mastodon_production = host=127.0.0.1 port=5432 dbname=mastodon_production user=mastodon password=password

listen_addrlisten_port 告诉 PgBouncer 从哪个地址/端口接收连接。默认值即可:

listen_addr = 127.0.0.1
listen_port = 6432

auth_type设为md5(假定你在userlist.txt使用md5格式

确保pgbouncer帐户为管理员:

接下来的部分极其重要! 默认连接池模式是基于连接session-based但是Mastodon需要基于事务transaction-based。换而言之当一个事务创建一个Postgres连接随之创建当事务完成该连接也随之结束。因此你需要把pool_modesession改为transaction

接下来,max_client_conn定义PgBouncer自身接受多少连接default_pool_size限制后台开启多少Postgres连接。在PgHero显示的连接数将与default_pool_size数目一致因为它不知道PgBouncer。

使用默认值启动即可,你可以随后调大他们:

max_client_conn = 100
default_pool_size = 20

完成更改后不要忘记重载reload或重启restartpgbouncer

sudo systemctl reload pgbouncer

调试,确保一切正常

你应该能像连接Postgres一样连接PgBouncer

psql -p 6432 -U mastodon mastodon_production

然后,使用你的密码登录。

你也可以检查PgBouncer日专就像这样

tail -f /var/log/postgresql/pgbouncer.log

配置 Mastodon 以连接 PgBouncer

首先,确保.env.production文件这样设置:

PREPARED_STATEMENTS=false

因为我们使用基于事务transaction-based的连接池我们不能使用参数化查询prepared statement

接下来配置Mastodon使用6432端口PgBouncer而不是5432端口PostgreSQL就可以了

DB_HOST=localhost
DB_USER=mastodon
DB_NAME=mastodon_production
DB_PASS=password
DB_PORT=6432

{{< hint style="warning" >}} 你不能使用pgBouncer来执行 db:migrate 操作。但是这个问题很容易解决。如果你的postgres和pgBouncer位于同一台主机只需要在执行任务时与 RAILS_ENV=production 一同定义 DB_PORT=5432 就可以了,例如:RAILS_ENV=production DB_PORT=5432 bundle exec rails db:migrate(如果主机不同,你也可以指定DB_HOST等等) {{< /hint >}}

管理 PgBouncer

最简单的重启方法:

sudo systemctl restart pgbouncer

但如果你设定了PgBouncer管理员帐户你也可以用管理员帐户连接

psql -p 6432 -U pgbouncer pgbouncer

然后执行:

RELOAD;

使用 \q 以退出。

单独的Redis缓存

Redis被广泛使用于应用但是某些用途比其他用途更重要。主页时间轴、列表时间轴、Sidekiq队列还有streaming API都是由Redis支持的这些是你不希望丢失的重要数据尽管丢失了也能存活不像PostgreSQL数据库的丢失——永远不要丢失PostgreSQL数据库。然而Redis也被用于易失性缓存。如果你正处于扩展阶段担心你的Redis能否处理所有事情你可以使用一个不同的Redis数据库来做缓存。在环境变量中你可以指定 CACHE_REDIS_URL 或分离形式,就像 CACHE_REDIS_HOSTCACHE_REDIS_PORT等等。未指定部分将会回落至没有前缀的相同设定值。

至于Redis数据库配置基本上你可以去除后台保存至磁盘因为重启致使数据丢失也没关系你可以以此节省一些磁盘I/O。你还可以添加最大内存限制和 key eviction policy对于这部分请参阅这个指南Using Redis as an LRU cache

只读副本Read-replicas

为了减轻你的Postgresql服务器负担你可以使用热流复制hot streaming replication只读副本read replica。有关示例请参见该指南。你可以给以下Mastodon用途使用副本replica

  • streaming API 服务器无需写入因此你可以将其直接使用副本replica。但由于 streaming API 服务器不经常查询数据库,这样的优化影响很小。
  • 使用 Makara 驱动 web 与 sidekiq 进程这样可以实现从主primary数据库写从副本replica读。让我们开始吧。

编辑 config/database.yml 文件,将 production 替换为如下内容:

production:
  <<: *default
  adapter: postgresql_makara
  prepared_statements: false
  makara:
    id: postgres
    sticky: true
    connections:
      - role: master
        blacklist_duration: 0
        url: postgresql://db_user:db_password@db_host:db_port/db_name
      - role: slave
        url: postgresql://db_user:db_password@db_host:db_port/db_name

确保URL指向PostgreSQL服务器所在位置。你可以添加多个副本replica。你可以本地安装一个pgBouncer该pgBouncer可被配置为根据数据库名称连接两个不同服务器例如“mastodon”连接主服务器“mastodon_replica”连接副本服务器这样上面文件中的两个URL可以使用同样用户名、密码、主机、端口不同数据库名称。可能的设置有很多有关Makara的更多信息请参阅其文档

{{< hint style="warning" >}} Sidekiq无法可靠的使用只读副本read-replicas因为即使是最微小的复制延迟也会导致查询不到相关纪录所致的任务失败。 {{< /hint >}}

{{< translation-status-zh-cn raw_title="Scaling up your server" raw_link="/admin/scaling/" last_tranlation_time="2020-05-06" raw_commit="ad1ef20f171c9f61439f32168987b0b4f9abd74b">}}