如何扩展 Mastodon 服务器
作者选择 Apache 软件基金会和自由开源基金来接收捐赠,作为 Write for DOnations 计划的一部分。
介绍
Mastodon 是一个开源的自托管社交网络。 Mastodon 是联合的,这意味着 Mastodon 的多个实例可以互操作, 允许来自不同服务器的用户相互通信,创建一个名为 fediverse 的网络。 Fediverse 是一个由互连服务器组成的网络,这些服务器使用 ActivityPub 协议相互通信。
随着 Mastodon 社区呈指数级增长,服务器上的负载也呈指数级增长。去年,由于用户活动高峰,Mastodon 服务器发生了多起宕机事件。为了防止 Mastodon 服务器在用户涌入期间宕机,需要对其进行扩展。
为了了解如何缩放乳齿象,您需要了解乳齿象是由什么组成的。 Mastodon 服务器由五个主要组件组成:Web 服务、StreamingAPI 服务、Sidekiq 服务、Redis 和 PostgreSQL。
或者,对象存储可以极大地提高静态媒体文件的性能并减少 Web 服务的负载。虽然不会提升性能,但 ElasticSearch 还可以启用全文搜索,而 LibreTranslate 可以让您的服务器自动翻译消息,使您的服务器变得更好一点。
注意: Mastodon 服务仅通过数据存储(Redis 和 PostgreSQL)进行通信。这为分布式设置提供了很大的灵活性,但在没有正确配置的情况下简单地将组件分布在多台机器上不会带来所需的性能提升。
在本教程中,您将了解 Mastodon 服务器的不同扩展技术:
- 增加数据库资源和可用连接
- 将 Sidekiq 队列拆分为多个进程
- 为每个 Sidekiq 队列配置线程和资源
- 添加对象存储以卸载Web服务
- 增加Web服务的线程和进程
如果您计划扩展 Mastodon 服务器以满足某些活跃用户的容量,我们建议您阅读整篇文章并扩展每个组件。 另一方面,如果您的目标是缩放特定组件 - 请随意跳转到相应的组件部分。 经验法则是将每台运行 Mastodon 组件的机器的平均负载保持在 60-70% 左右。有时,不良的服务配置可能会导致性能低下以及平均负载低。 下面的每个部分都包含检测此类情况的症状。
注意:本文包含针对在 systemd 服务上运行的 Mastodon 服务器(例如 Mastodon Droplet 1-Click)的示例。如果您有其他类型的 Mastodon 设置(Docker、K8s 等),请考虑使用相应的配置方法。
提高数据库性能
PostgreSQL 是 Mastodon 服务器的主要事实来源。它包含所有用户的凭据、嘟嘟声、提升、用户关系等。确保数据库的安全和备份是您的首要任务。
Mastodon 使用大量的数据库连接。连接匮乏的症状包括 Sidekiq 性能不佳、提要更新延迟数小时、整体速度缓慢,甚至整个服务器变得无法访问。
在本部分中,您将计算服务器所需的连接数并相应地配置数据库。无需额外资源,它将使您的服务器免于连接匮乏,从而影响所有 Mastodon 服务的性能。
信息:Mastodon 服务器所需的连接数绝不能超过 PostgreSQL 的 max_connections 变量。另外,max_connections 应尽可能低以避免数据库争用。
要计算 Mastodon 服务器所需的连接总数,您需要计算每个组件所需的连接数:
- 对于每个 Web 服务实例,所需的连接数是 MAX_THREADS 乘以 WEB_CONCURRENCY。
- 对于每个 StreamingAPI 实例,所需的连接数是 STREAMING_CLUSTER_NUM 乘以 DB_POOL。
- 对于每个 Sidekiq 实例,所需的连接等于 DB_POOL。
信息:上面的所有变量都可以在相应组件的环境中找到。在本文中,您将使用此处列出的每个变量。
将所有这些数字相加,并添加额外的 20 个连接以进行维护。这是您的 max_connections 值。
信息:正确配置数据库是扩展 Mastodon 的首要任务,但要确定 max_connections 数量,您必须首先知道如何扩展其他服务。 创建有关如何扩展其他服务的计划(您将在下一节中找到)后,您可以返回此处完成max_connections的计算。
现在您知道了 max_connections 的值,您将使用它来配置数据库。
生成配置的一个好方法是使用名为 PGTune 的服务。 打开 PGTune 页面后,您将看到必须填充的配置字段:
- 数据库版本:在此处指定您的 Mastodon 服务器使用的 PostgreSQL 版本。您可以在运行 PostgreSQL 的机器上使用以下命令找到它:
pg_config --version
- 操作系统类型:运行 PostgreSQL 的计算机的操作系统。
- 数据库类型:PostgreSQL 将执行的工作负载类型。对于 Mastodon,请选择在线事务处理系统(将来的 OLTP),因为 Mastodon 会创建大量连接。
- 总内存 (RAM):PostgreSQL 将使用的内存量。尝试分配一台机器最多一半的物理内存,但如果其他服务正在同一台机器上运行 - 确保不要超过总 RAM。例如,在具有 8 GB RAM 且仅有 PostgreSQL 的计算机上,我们在 PGTune 中指定 4 GB。
- CPU 数量:PostgreSQL 将使用的 CPU 核心数量。由于 OLTP 受 CPU 限制,因此我们强烈建议将此数字设置为与您的计算机支持的 CPU 线程数一样高。
- 连接数:此处为max_connections。
- 数据存储:运行 PostgreSQL 的计算机上的数据存储设备类型。
例如,以下是 8 GB RAM 计算机、8 个线程和 420 个 max_connections 上的配置:
单击生成后,您将收到配置参数,应将其添加到您的postgresl.conf文件中。
在运行 PostgreSQL 的计算机上打开 postgresql.conf:
sudo nano /etc/postgresql/major version of your PostgreSQL/main/postgresql.conf
例如,如果您运行的是 PostgreSQL 版本 15.x,则此文件的位置将为 /etc/postgresql/15/main/postgresql.conf。
接下来,对于 PGTune 生成的每个参数,您将在 postgresql.conf 中搜索相同的参数并更改其值。在 nano 中使用 Ctrl+W 进行搜索,在 vi/vim 中使用 Esc+/ 进行搜索。如果您的 postgresql.conf 中不存在某些参数,您可以在文件中的任何位置创建它。
最后,重新启动 PostgreSQL 服务以应用更改:
sudo service postgressql restart
现在您知道如何配置 PostgreSQL 以获得更好的 Mastodon 性能以及如何应用新配置。在下一部分中,您将找到计算 max_connections 所需的所有变量的准确值。
完善 Sidekiq 队列
Sidekiq 是一个 Ruby 作业调度程序和工作人员。它负责执行后台作业,例如在服务器之间传播帖子、生成链接预览、处理点赞等。
Sidekiq 使用 Redis 作为作业的队列管理器,并使用 PostgreSQL 来保存作业结果。如果连接了多台服务器(用户正在关注其他服务器上的人),则会创建大量作业以将必要的数据从一台服务器传播到另一台服务器。
Sidekiq 瓶颈的症状包括提要更新延迟较长、Sidekiq 队列堵塞以及数据库负载持续存在。
在本节中,您将估算服务器所需的 Sidekiq 队列的大小以及运行它们所需的物理机数量。
Mastodon 有多个 Sidekiq 队列。然而,其中一些资源更加密集,会完全加载 CPU,而另一些则几乎不会造成任何百分比的负载。下表包含 Mastodon 所需的所有队列的描述及其资源优先级,与低优先级队列相比,高优先级队列将使用更多的 CPU:
default
优先级:最高
角色:处理影响本地用户的所有任务。
ingress
优先级:高
角色:处理传入的远程活动。优先级低于默认队列,因此本地用户在服务器负载不足时仍然可以看到他们的帖子。请记住,ingress 队列是高度 CPU 密集型的。
push
优先级:中
角色:将有效负载传送到其他服务器。
pull
优先级:中
角色:处理诸如处理导入、备份、解析线程、删除用户和转发回复等任务。
mailers
优先级:低
角色:发送电子邮件。
scheduler
优先级:最低
角色:管理 cron 作业,例如刷新趋势标签和清理日志。
警告: scheduler 队列绝不能扩展到多个进程。 Mastodon 服务器只应存在 1 个运行 scheduler 的进程。
上表将帮助您正确分配机器,但是如何配置队列本身呢?队列可以有效服务的活动用户数量受到限制,并且此限制与特定队列具有的线程数相关。分配的线程越多 - 某些队列可以处理的活动用户就越多。队列的类型也会影响此限制,与其他队列相比,某些队列需要更少的线程来服务相同数量的用户。下图描述了这种多维关系。
X 轴表示 Mastodon 将服务的预期活跃用户数,而 Y 轴表示每个队列服务相应数量的活跃用户所需的估计线程数:
根据您的服务器社区,push 或 pull 队列可能具有不同的优先级。如果您的社区与其他联盟高度互联,请优先考虑 push 队列。否则,如果您的服务器特定于某些感兴趣的内容,则您可以预期会有大量本地活动,并优先考虑拉。
注意:不同的服务器有不同的使用模式和负载分布。尝试通过分析您的服务器中的用户会提升或喜欢其他服务器上的用户的可能性来预测服务器的使用模式。
例如,如果您的服务器涵盖特定的科学主题,则来自您服务器的用户将主要相互通信。另一方面,如果您的服务器是个人政治博客,那么来自您服务器的用户可能更有可能支持其他政客。作为 Mastodon 管理员,您需要监控自己服务器的负载并相应地扩展组件。
关于 Sidekiq 队列的最后一个重要注意事项是,Sidekiq 的约 10-15 个线程需要 1 GB RAM。由此得出一个关系:
警告: Single Sidekiq 服务不应使用超过 50 个线程。要服务 60 个线程 - 运行 2 个服务,每个服务有 30 个线程。
例如,我们估计有 15000 名主要仅使用本地联合的活跃用户。 根据上图我们需要:
默认:总共大约 70 个线程,2 个服务,每个服务 35 个线程。ingress:总共大约 50 个线程,2 个服务,每个服务 25 个线程。pull:总共大约 40 个线程,1 个服务包含所有 40 个线程。push:总共大约 30 个线程,1 个服务包含所有 35 个线程。mailer:总共大约 20 个线程,1 个服务包含所有 20 个线程。scheduler:总共 5 个线程,1 个服务包含所有 5 个线程。
请记住,我们的用户不经常使用外部联合,因此我们优先考虑pull队列而不是push。
由于scheduler队列是优先级最低的队列,我们可以将它与default队列一起运行,它不会影响default队列全部。它们总共需要 70 + 5=75 个线程,相当于大约 8GB 的 RAM。由于它只是一个繁重的队列,因此我们可以使用一台 4 核 8GB 机器。 ingress 和 mailer 是高优先级和低优先级队列,这意味着与单个 default 队列相比,它们需要更少的 CPU 资源,但我们仍然会使用4核机器。它们的线程总数为 25 + 20=45,大约为 6GB RAM。 pull 和 push 队列都是中等优先级,与 ingress 和 mailer 相比,它们对 CPU 的消耗更大,所以我们将再次使用 4 核。线程数量为 40 + 30=70,相当于 8GB RAM。
综上所述,如果我们计划为 15000 个活跃用户提供服务,则对于 Sidekiq 配置,我们总共需要 3 台机器:
- 一台 4c/8GB 机器,为
default队列的 2 个服务(每个服务有 35 个线程)和scheduler队列的 1 个服务(每个服务为 5 个线程)提供服务。 - 一台 4c/8GB 机器,可提供 1 个具有 50 个线程的
ingress队列服务和 1 个具有 20 个线程的mailer队列服务。 - 一台 4c/6GB 机器可提供 1 个具有 40 个线程的
pull队列服务和 1 个具有 30 个线程的push队列服务。
注意:确定所需核心数量的最佳方法是观察运行 Sidekiq 的计算机上的平均负载。 如果平均负载超过80%,则需要更多CPU核心。如果核心数量已经足够高(例如超过 8 个核心),您可以尝试创建另一台具有相同配置的机器,无需任何类型的负载平衡,它会分配负载并为您提供另一个维度规模。不要忘记不要多次运行 scheduler 队列。
缩放 Sidekiq
为了充分利用硬件资源,Sidekiq 需要配置适当数量的线程并在进程级别进行扩展。在本节中,您将了解如何准确设置 Sidekiq 队列的线程数以及如何使用服务模板在同一台计算机上运行多个队列。
增加单个 Sidekiq 进程使用的线程数
服务是systemd可以管理、记录、自动重启等的资源。将可执行文件包装在服务中是部署应用程序的最简单方法之一。 Systemd 服务是运行 Sidekiq 队列的最常见方式。 Sidekiq 服务的位置取决于 Mastodon 安装的类型。例如,如果您使用 Mastodon Droplet 1-Click,则可以在以下位置找到 Sidekiq 服务文件:
cat /etc/systemd/system/mastodon-sidekiq.service
让我们快速浏览一下服务文件的顶部:
[Unit]
Description=mastodon-sidekiq
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=25"
Environment="MALLOC_ARENA_MAX=2"
Environment="LD_PRELOAD=libjemalloc.so"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25
...
[Install]
WantedBy=multi-user.target
我们的注意力应该集中在两个特定领域:ExecStart 和Environment。 ExecStart 定义服务启动或重新启动时运行的服务起点。 Environment 定义传递给 ExecStart 的环境变量。
要扩展单个 Sidekiq 进程,您应该增加 Sidekiq 将使用的线程数。该数字由 ExecStart 字段中的 -c 参数控制。不要忘记保持 DB_POOL 环境变量与 -c 参数同步。 例如,我们将线程数增加到 45。您将更改 -c 参数以及 DB_POOL 的值:
[Unit]
Description=mastodon-sidekiq
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=40"
Environment="MALLOC_ARENA_MAX=2"
Environment="LD_PRELOAD=libjemalloc.so"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 40
...
[Install]
WantedBy=multi-user.target
信息:DB_POOL 环境应始终与 -c 参数的值相同(上例中的 40)。让它变小会导致 Sidekiq 性能问题,而让它变大则会给数据库带来额外的负载。
对服务文件进行任何更改后,请确保重新加载单元文件并重新启动 Sidekiq 服务:
sudo systemctl daemon-reload
sudo systemctl restart mastodon-sidekiq.service
通过应用本部分的更改,您增加了 Sidekiq 使用的线程数量,使其能够为更多用户提供服务。
为单个 Sidekiq 实例指定特定队列
我们首先分析默认的 Sidekiq 服务文件。如果您使用 Mastodon Droplet 1-Click,您可以在以下位置找到 Sidekiq 服务文件:
cat /etc/systemd/system/mastodon-sidekiq.service
如您所知,Mastodon 将 Sidekiq 数据分为多个队列。默认情况下,服务文件中没有显式指定队列。
[Unit]
Description=mastodon-sidekiq
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=25"
Environment="MALLOC_ARENA_MAX=2"
Environment="LD_PRELOAD=libjemalloc.so"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25
...
[Install]
WantedBy=multi-user.target
没有明确的队列意味着 Sidekiq 将为所有具有某些默认优先级的队列提供服务。由于即使单个 Sidekiq 队列也是资源密集型的,因此在单个 Sidekiq 实例上运行所有队列并不理想。 您想要实现的是将 Sidekiq 队列拆分为多个 Sidekiq 实例。这将允许您指定每个队列的确切线程数,并且还允许您在多台计算机上运行不同的队列。 希望覆盖默认的 Sidekiq 行为只需要向 ExecStart 字段添加 -q 参数即可。
例如,让 Sidekiq 仅服务于 ingress 队列:
[Unit]
Description=mastodon-sidekiq
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=25"
Environment="MALLOC_ARENA_MAX=2"
Environment="LD_PRELOAD=libjemalloc.so"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25 -q ingress
...
[Install]
WantedBy=multi-user.target
通过指定 -q ingress,您可以告诉 Sidekiq 仅服务于 ingress 队列,而不提供其他服务。
警告:上面的示例将使除ingress之外的所有队列都未处理,这意味着Mastodon将无法正常运行。确保每个队列至少覆盖一次。下一节包含有关如何在单台计算机上运行 Sidekiq 服务的多个实例的指南。
让 Sidekiq 服务仅处理单个队列有几个优点:更容易处理特定队列的日志,它提供每个队列的管理和线程控制,并允许通过在不同的机器上运行不同的队列来进行分布式设置。总的来说,它被认为是扩展 Sidekiq 队列的主要实践。 然而,将所有硬件资源分配给单个队列并不总是有效的,这就是为什么在下一节中您将学习如何在一台机器上单独运行多个队列
使用模板在一台计算机上运行 Sidekiq 的多个实例
仅运行 Sidekiq 的单个实例效率较低。要进一步扩展 Sidekiq,您可以同时运行 Sidekiq 的多个实例。 由于 systemd 服务是运行 Sidekiq 的最常见方式,因此您将学习如何创建服务模板以简化在单台计算机上运行 Sidekiq 的多个实例。
服务模板允许我们从单个服务文件创建多个服务。
首先,让我们创建现有 Sidekiq 服务文件的副本:
cp /etc/systemd/system/mastodon-sidekiq.service /etc/systemd/system/mastodon-sidekiq-template.service
这将创建一个名为 mastodon-sidekiq-template.service 的新文件,它是现有 Sidekiq 服务的副本。 您将修改此副本以将其转换为模板。模板由模板说明符定义,在本文中您将使用两个特定的说明符:%i 和 %j。
- %i 是实例名称。对于实例化服务,这是第一个“@”字符和类型后缀之间的字符串。
- %j 是前缀的最后一个组成部分。这是最后一个“-”和前缀名称末尾之间的字符串。
听起来很混乱?让我们进入实际部分以更好地理解它。
首先,打开新的服务文件进行编辑:
sudo nano /etc/systemd/system/mastodon-sidekiq-template.service
现在,将服务文件中的一些值更改为模板说明符:
- 描述字段应包含 %j 说明符,以便于服务的跟踪和维护。
- DB_POOL 环境变量应等于 %i 说明符。
- ExecStart 中的 -c 参数应等于 %i
- ExecStart 中的 -q 参数应等于 %j
[Unit]
Description=mastodon-sidekiq-%j-queue
After=network.target
[Service]
...
Environment="DB_POOL=%i"
Environment="MALLOC_ARENA_MAX=2"
Environment="LD_PRELOAD=libjemalloc.so"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c %i -q %j
...
[Install]
WantedBy=multi-user.target
正如您可能猜到的,%i 说明符将包含 Sidekiq 的线程数,%j 说明符将包含 Sidekiq 队列的名称。
那么,如何设置这些变量呢?说明符被服务文件中的特定部分替换。
让我们使用此模板为所需的 Sidekiq 配置创建服务文件。
首先,复制模板以指定要在此计算机上运行的队列。例如,要运行 default 和 scheduler 队列:
cp /etc/systemd/system/mastodon-sidekiq-template.service /etc/systemd/system/mastodon-sidekiq-default@.service
cp /etc/systemd/system/mastodon-sidekiq-template.service /etc/systemd/system/mastodon-sidekiq-scheduler@.service
对于队列的名称,您可以使用 default、ingress、push、pull、 之一>邮件程序,调度程序。
您可能已经注意到,在 @ 符号之后没有指定任何内容。这是因为您将在启用服务本身时指定此参数。 现在要启用新服务,让我们使用 20 线程作为默认队列,使用 5 线程作为调度程序队列:
sudo systemctl enable mastodon-sidekiq-default@20.service
sudo systemctl enable mastodon-sidekiq-scheduler@5.service
最后,启用新服务后,您可以使用以下命令立即运行所有服务:
sudo systemctl start mastodon-sidekiq*
至此,您已经成功创建了一个模板服务文件,并使用它来运行具有不同队列和线程的 Sidekiq 的多个服务。
更改正在运行的模板服务的配置
例如,如果您希望将模板化 default 服务的线程数从 20 更改为 40,则应首先禁用现有服务:
sudo systemctl stop mastodon-sidekiq-default.service
sudo systemctl disable mastodon-sidekiq-default@20.service
请注意,您如何只为 disable 命令指定线程数,而不是为 stop 指定线程数。
禁用旧的 push 服务后,您可以创建一个具有 40 线程而不是 20 的新服务:
sudo systemctl enable mastodon-sidekiq-default@40.service
sudo systemctl start mastodon-sidekiq-default.service
此时,您已成功更改现有 systemd 服务的线程数。
运行同一 Sidekiq 队列的多个服务
如您所知,Sidekiq 的单个实例不应超过 50 个线程。运行某个队列的 60 个线程需要将其拆分为 2 个服务,每个服务 30 个线程。
为此,您需要使用同一队列多次复制模板,但添加索引。索引只是一个区分每个服务文件的数字。 多次复制初始模板,但每次重复相同队列时都会增加索引。例如,创建 default 队列的 2 个服务文件:
cp /etc/systemd/system/mastodon-sidekiq-template.service /etc/systemd/system/mastodon-sidekiq-1-default@.service
cp /etc/systemd/system/mastodon-sidekiq-template.service /etc/systemd/system/mastodon-sidekiq-2-default@.service
警告:请勿在队列名称后附加索引,如下所示:/etc/systemd/system/mastodon-sidekiq-default-2@service。这将使模板将 2 视为队列的名称,这将不可避免地使其失败。仅在队列名称之前插入索引。
现在,让我们为默认队列的第一个实例启用 40 个线程,为第二个实例启用 60 个线程:
sudo systemctl enable mastodon-sidekiq-1-default@40.service
sudo systemctl enable mastodon-sidekiq-2-default@60.service
最后,启用服务后,您可以使用以下命令运行所有服务:
sudo systemctl start mastodon-sidekiq*
至此,您已成功创建同一队列的多个实例,从而允许您正确拆分大量线程。
您了解了设置 Sidekiq 服务的多种方法。在某些情况下,单个默认服务就足够了,其他情况下则需要在一台计算机上提供多个服务,有些甚至需要在多台计算机上提供同一队列的多个服务。这完全取决于您想要支持的活跃用户数量。
添加对象存储
对象存储(或简称存储桶)允许存储服务器用户上传的媒体文件。这包括照片、视频、GIF、音频文件等。
从文件系统迁移到对象存储有助于提高存储速度和容量,但更重要的是,它减少了 Mastodon 服务的负载。此外,大多数云提供的对象存储还提供 CDN,这将更快地将媒体文件传递给用户。
注意: Mastodon 使用 S3 兼容接口,这意味着您的对象存储提供商必须支持 S3 接口并提供 S3 存储凭据的映射。
如果您在 Mastodon 初始化期间不小心错过了对象存储配置,您可以直接将必要的变量添加到运行 Web 服务的计算机的配置中,因为对象存储仅由 Web 服务使用。
警告:通过更改对象存储,您将丢失服务器上的所有现有媒体文件。
在运行 Web 服务的计算机上,如果您使用的是 Mastodon Droplet 1-Click,请在您首选的文本编辑器中打开 .env.product,env.product 位于/home/mastodon/live:
sudo nano .env.production
将以下行添加到您的 .env.product 文件中的任意位置,用您自己的信息替换突出显示的文本。如果这些变量已经存在 - 这意味着在设置过程中配置了对象存储,如果值不正确,您仍然可以更改它们:
...
S3_ENABLED=true
S3_PROTOCOL=https
S3_BUCKET=your bucket name
S3_REGION=your bucket region
S3_HOSTNAME=your bucket hostname
S3_ENDPOINT=your bucket endpoint
AWS_ACCESS_KEY_ID=your bucket secret ID
AWS_SECRET_ACCESS_KEY=your bucket secret key
...
上述变量代表S3接口连接参数。确保对来自对象存储提供商的连接参数使用正确的 S3 映射。
然后保存并退出编辑器。
确保在保存更改后重新启动 Web 服务:
sudo systemctl restart mastodon-web.service
现在您知道如何为 Mastodon 手动配置对象存储,以防自动设置失败、人为错误或手动安装。对象存储将有助于减少 Mastodon Web 服务的负载,并为服务器上的媒体文件提供更好的上传/下载速度。
扩展 Web 服务
Web 服务是一个 Ruby-on-Rails HTTPS 服务器,为 Mastodon UI 提供服务并处理来自用户的请求。 Web 服务的负载与活跃用户数量成正比。每个线程可以同时应答一个请求。如果所有线程都忙,则下一个请求必须等待。如果请求等待时间过长,则会因超时错误而被取消。 Web 服务瓶颈可以通过较长的请求处理时间来识别:页面打开缓慢、帖子创建明显延迟或日志中出现超时错误。
警告:Web 服务仅强制执行 HTTPS,这意味着无法在托管 Web 服务的多台计算机之间的负载平衡器上使用 SSL 终止。
为了让Web服务能够处理更多的用户,您需要增加服务使用的线程总数。这可以通过增加 WEB_CONCURRENCY (工作线程数)和/或 MAX_THREADS (每个工作线程的线程数)的环境变量来完成。每个工作线程都有 MAX_THREADS 数量的线程,因此线程总数为 WEB_CONCURRENCY 乘以 MAX_THREADS。
增加 MAX_THREADS 往往会消耗更多 CPU,而增加 WEB_CONCURRENCY 往往会消耗更多 RAM。 Mastodon 版本 4.0.2 的平均估计单个工作人员需要 2-3 GB RAM。在上面的示例中,WEB_CONCURRENCY=3 所需的 RAM 估计量为 9 GB。 对于 MAX_THREADS,我们建议从一些通用值(如 15)开始,然后增加它,直到平均使用 70% 的 CPU。这意味着您需要观察运行 Web 服务的计算机,以了解是否可以压缩更多线程。
注意:下面是 systemd Web 服务配置的演示片段。如果您使用其他技术来运行 Web 服务(Docker、K8s 等),请根据您的技术环境规范调整 WEB_CONCURRENCY 和 MAX_THREADS 变量。
首先,我们打开Web服务文件:
sudo nano /etc/systemd/system/mastodon-web.service
您将看到一个 Web 服务 systemd 文件,如下所示:
[Unit]
Description=mastodon-web
After=network.target
[Service]
...
Environment="LD_PRELOAD=libjemalloc.so"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
ExecReload=/bin/kill -SIGUSR1 $MAINPID
...
[Install]
WantedBy=multi-user.target
现在,在 ExecStart 字段上方附加两个带有 WEB_CONCURRENCY 和 MAX_THREADS 变量的额外字段:
[Unit]
Description=mastodon-web
After=network.target
[Service]
...
Environment="LD_PRELOAD=libjemalloc.so"
Environment="WEB_CONCURRENCY=your concurrency value"
Environment="MAX_THREADS=your threads value"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
ExecReload=/bin/kill -SIGUSR1 $MAINPID
...
[Install]
WantedBy=multi-user.target
这些新字段将使用您自己的值覆盖 WEB_CONCURRENCY 和 MAX_THREADS 的默认值。
保存并退出编辑器。
确保在保存更改后重新加载单元文件并重新启动服务:
sudo systemctl daemon-reload
sudo systemctl restart mastodon-web.service
注意:自 2017 年以来,Web 服务的性能几乎翻了一番,我们强烈建议大家监控硬件使用情况,以确定是否应该分配更多或更少的资源。
此时,您已经增加了 Web 服务配置的默认值。这使您的 Mastodon 前端支持更多活跃用户。请记住,始终要有额外的性能裕度,以确保您的 Mastodon 服务器不会因大量用户涌入而受到限制。
提高 StreamingAPI 吞吐量
StreamingAPI 是一个 NodeJS 服务器,托管用于实时更新的 API。它允许用户直接从服务器接收事件流。 StreamingAPI 受到它可以同时服务的用户数量的限制。该限制绑定到 STREAMING_CLUSTER_NUM 环境变量。
StreamingAPI 瓶颈可以通过查看服务日志来识别。如果类似 node[1201554]: ERR! error:抱歉,日志中已经出现太多客户端,这意味着使用StreamingAPI的用户数量超出了它的处理能力,新用户会自动断开连接。
扩展 StreamingAPI 非常简单。 增加 STREAMING_CLUSTER_NUM 环境变量将允许 StreamingAPI 为更多用户提供服务。 如果您在日志中看到大量错误:抱歉,客户端数量过多消息,请将 STREAMING_CLUSTER_NUM 增加 1.5 倍至 2 倍。 例如,如果 STREAMING_CLUSTER_NUM 的当前配置为 2,请将变量更新为 4
在运行StreamingAPI的机器上,打开StreamingAPI服务文件:
sudo nano /etc/systemd/system/mastodon-streaming.service
编辑 STREAMING_CLUSTER_NUM 变量的值:
[Unit]
Description=mastodon-streaming
After=network.target
[Service]
...
Environment="STREAMING_CLUSTER_NUM=your new value"
ExecStart=/usr/bin/node ./streaming
...
保存文件并确保在保存更改后重新加载单元文件并重新启动服务:
sudo systemctl daemon-reload
sudo systemctl restart mastodon-streaming.service
此外,默认情况下 StreamingAPI 没有设置 DB_POOL 变量。如果没有显式设置此变量,StreamingAPI 将使用 10 连接。显式增加 DB_POOL 变量而不增加 STREAMING_CLUSTER_NUM 变量,但如果您想这样做,只需在 StreamingAPI 服务文件中创建一个新的环境变量即可。
在运行StreamingAPI的机器上,打开StreamingAPI服务文件:
sudo nano /etc/systemd/system/mastodon-streaming.service
添加新的环境变量DB_POOL:
[Unit]
Description=mastodon-streaming
After=network.target
[Service]
...
Environment="DB_POOL=your value"
Environment="STREAMING_CLUSTER_NUM=your value"
ExecStart=/usr/bin/node ./streaming
...
保存文件并确保在保存更改后重新加载单元文件并重新启动服务:
sudo systemctl daemon-reload
sudo systemctl restart mastodon-streaming.service
这将覆盖 DB_POOL 的默认值,并使您更清楚地了解 StreamingAPI 实例需要多少个数据库连接。
注意:如果您没有明确指定DB_POOL的值,则在计算时使用值10作为DB_POOL >max_connections 变量。
您现在已经更新了 StreamingAPI 配置以实现更好的吞吐量。这将帮助您的 StreamingAPI 为更多并发用户提供服务而不会失败。或者,您可以明确指定 DB_POOL 环境变量来优化数据库配置例程,或者将其保持不变并使用 10 作为 StreamingAPI 的 DB_POOL 值。
结论
在本教程中,您学习了如何识别和解决 PostgreSQL、Sidekiq、Web 服务和 StreamingAPI 中的瓶颈。现在您可以设置新服务器或扩展现有服务器。
扩展方法总是可以改进和细化,例如,复杂的 Sidekiq 配置可以进一步模板化。 官方 Mastodon 扩展指南包含有关如何扩展和优化服务器的一些额外观点。
改善服务器用户体验的另一个好方法是使用 ElasticSearch 启用全文搜索。 这将允许用户从他们的状态、提及、收藏夹和书签中查找结果。
通过启用 LibreTranslate,还可以让 Mastodon 将嘟嘟声和其他消息翻译成用户语言。





