Help us understand the problem. What is going on with this article?

Mastodon鯖を速くしたいときに踏みがちな罠(SidekiqとWeb)

概要

Mastodon鯖を速くしたくていろいろググるとなんか出るけど、効果がなかったり逆効果になったりしがちなやり方と、それよりはマシなやり方を書いていく。

Sidekiq

MastodonにおけるSidekiqは、他鯖からのトゥートをTLに流したり、逆に自鯖のトゥートを他鯖に配信したりする。
Fediverseが賑わったり、あるいは鯖をしばらく落としてから復旧すると、他鯖からのトゥートが一斉に降ってきて処理が詰まる。
あるいはフォローインポートや垢消しがあると、他鯖への配信処理が一気に走って詰まる。

よくない方法

  • Sidekiqの並列数(とDB_POOL)を(大幅に)増やす。
mastodon-sidekiq.service
# 関係ない行は省略
[Service]
Environment="DB_POOL=50"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 50

PostgresqlとSidekiqのメモリ消費が並列数相応に増える。
しかし、性能改善にはあまり効果がない。というのも、Rubyのプロセスは基本的に1CPUコアしか使えないのである。Mastodonのデフォルトである5並列から増やしても、すぐにCPUが律速になってしまう。少し増やすだけなら効果はあるかもしれないが、この例のように大幅に(5 → 50)増やす意味はない。
さらに悪いことに、小さい鯖でこのような設定をすると、メモリ不足を起こしてかえって遅くなってしまう。

また、sidekiq

ましな方法

  • Sidekiqプロセス自体を複数作る。
  • Sidekiqキューを複数のプロセスに振り分ける(CPUやメモリに余裕があれば)。
mastodon-sidekiq-default.service
#他の行はデフォルトの設定からコピーする
[Unit]
Description=mastodon-sidekiq-default
[Service]
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -q default
mastodon-sidekiq-pull.service
#他の行はデフォルトの設定からコピーする
[Unit]
Description=mastodon-sidekiq-pull
[Service]
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -q pull
mastodon-sidekiq-push-mailers.service
#他の行はデフォルトの設定からコピーする
[Unit]
Description=mastodon-sidekiq-push-mailers
[Service]
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -q push -q mailers

MastodonはSidekiqキューを以下の4つに分けている。
それぞれの役目は非常に大雑把にいうとこうなる。

  • default: ↓以外全部
  • push: 他鯖にトゥートを配信したりする
  • pull: 他鯖のトゥートを保存したりする
  • push: 連合とのやりとりのうち、優先度が高いもの(トゥートの配信など)
  • pull: 連合(同文)、優先度が低いもの(他鯖のトゥをTLに反映する、トゥ消しのうちBTやリプライしてきた相手のTLから消す処理など)
  • mailers: メールを送るなど

MastodonのSidekiqキューの名前は嘘つきと化しており、issueが立つほどである(そして放置されている)
https://github.com/tootsuite/mastodon/issues/11175

defaultとpullを詰まらせると、自鯖のタイムラインが崩れるので、詰まらせてしまうのは望ましくない。(本当は全部…と言いたいところだが、mailersはどうせ暇だし、pushが詰まっても他鯖のタイムラインが崩れるが自鯖には影響はない。)
そこで、この例ではdefaultとpullは専用のプロセスで動かし、pushとmailersは同じプロセスで動かしている。このようにすると、例えばpushキューが詰まっても、defaultやpullは詰まらないので、連合タイムラインの崩壊を軽減したりできる。
なにより、プロセスを複数建てたので、複数のCPUコアの処理能力をSidekiqに活用できるようになる。
さらに速くしたいときは、同じキューに対応するプロセスを複数建ててもいいが、メモリ不足には注意が必要。

一方、メモリが足りない場合や、CPUが余ってるのにSidekiqが詰まる場合は、キューを分割しないで、単にsidekiqをCPUコア数分だけ建てるとよい。このようにすると、例えば連合タイムラインが速くなるとpullキューに大量のジョブが貯まる(→詰まる)が、全sidekiqがpullキューを受け付けていれば、全てのCPUコアの能力をpullキューのために活用できる。この場合は他のキューも同様に詰まってしまうが、遅延が増え続けてタイムラインが使い物にならなくなるよりはマシである。

pushキューに限っては、遅い鯖がある場合にはスレッド数を増やすのも意味がある(遅い鯖の影響でいくつかスレッドが詰まっても全体は詰まらない)…はずなのだが、手元では増やしても全くといっていいほど効果がなかった。

キュー毎にSidekiqを分けたりする効果についてはこの記事が詳しい。
https://logmi.jp/tech/articles/200000

ついでにjemallocを使わせてメモリを節約するのもよい。

mastodon-sidekiq-*.service
[Service]
#Ubuntuなどの場合
Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so"

#Fedoraなどの場合
Environment="LD_PRELOAD=/usr/lib64/libjemalloc.so"

#他の行は使い回す

Puma(web)

WebUIの表示、ストリーミング以外のタイムライン等の取得、書き込みの受け付けなどを行う。

よくない方法

  • MAX_THREADSを(大幅に)増やす。
  • DB_POOLの値を不適切に増やす。
mastodon-web.service
# 関係ない行は省略
[Service]
Environment="WEB_CONCURRENCY=4"
Environment="MAX_THREADS=10"
Environment="DB_POOL=40"

Sidekiqと同様に、Rubyのプロセスは1CPUコアしか使えないので、MAX_THREADS(各プロセス内での並列数)を増やすのはあまり効果がない。

そして、この例ではDB_POOLの設定の仕方を間違えている。
mastodon-webのDB_POOLは、Pumaの各プロセス毎に適用されるので、この例では 4プロセス * 40接続 = 160接続 まで増やすことを許可してしまっている。
実際にそのような状況になることはおそらくないだろうが、もし接続数が160に達したら、メモリ不足はもとより、Postgresqlの接続数制限に引っかかって鯖がまともに動かなくなるだろう。

mastodon-webのDB_POOLのデフォルト値は「MAX_THREADSの値を使い回す」(この例なら10になる)なので、ほとんどの場合はDB_POOLを設定する必要はない。

ましな方法

  • WEB_CONCURRENCY(プロセス数)を増やす。
mastodon-web.service
# 関係ない行は省略
[Service]
Environment="WEB_CONCURRENCY=4"

ちなみにWEB_CONCURRENCYの初期値は2である。
なお、CPUコア数より多くするのは、基本的に効果がないと考えていい。
もちろんメモリ不足にも注意。jemallocはここでも有効。

そもそも

本当にこれらが遅い原因なのかは念入りに調べる必要がある。他にも…

  • 回線が遅い
  • CPUが遅い
    • 特に1コアだと、画像の圧縮(imagemagickのconvert)で詰まりがち
    • VPSの場合はCPUクレジットにも注意
  • メモリがどうしようもなく足りない
    • Swapは多めに確保して、RubyがOSに返せない(確保してるけど使ってない)メモリをSwapに逃がしてやる
    • Ruby 2.7以前ではコンパクションがないため、OSに返せないメモリが発生しやすい(Mastodon v3.1.4時点ではRuby 2.6.6を使ってる)
    • Rubyにjemallocを使わせる
    • それでもダメなら、スレッド数やプロセス数を絞ってメモリを節約した方がかえって速くなるかも
  • DBをHDDに載せてる
    • SSDに載せよう
  • 鯖じゃなくてブラウザを動かしてるPCが遅い
  • 遅いのは自鯖じゃなくて相手の鯖だった

いろいろある(多分

204504bySE
TwiGaTenとか動かしてる。
https://204504byse.info/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした