Mastodonを設置したときのメモ

Mastodonは公式ドキュメントが比較的充実しているので設置そのものは簡単な部類です。

mastodon.juggler.jpは4/12に稼働開始しました。特に人を増やす予定もなかったのですが、当時の日本サーバ群は色々と不安定だったので避難所的な使われ方をして人数が増えてしまいました。その頃に発生した問題についてメモしておきます。

作成時に行っておくと良い作業

masterブランチを使わない

Mastodonのmasterブランチは開発ブランチです。使ってはいけません。
最新のタグをチェックアウトしましょう。

git clone https://github.com/tootsuite/mastodon.git
cd mastodon
git checkout $(git describe --tags `git rev-list --tags --max-count=1`)
ボリューム永続化のすすめ

git update-index --skip-worktree docker-compose.yml してから docker-compose.yml を編集します。

ファイル中に指定されているボリュームは次の5か所です。

  • ./postgres:/var/lib/postgresql/data
  • ./redis:/data
  • ./public/assets:/mastodon/public/assets
  • ./public/system:/mastodon/public/system
  • ./public/system:/mastodon/public/system

ただし最初の2つはコメントアウトしないとホスト側フォルダに保存されません。コンテナ自体にデータが保存されるため、コンテナが削除された時点でpostgresやredisのデータが消えてしまいます。

「### Uncomment to enable DB persistance」の下の2行 x 2か所のコメントを外します。こうしておくとコンテナをdown やrm してもホスト上にフォルダがそのまま残っているので、コンテナをいつ作り直しても問題ありません。まとめてtarできるので管理も楽になります。

もし postgresやredis のボリュームを指定せずに始めてしまった場合は、コンテナが消える前に(stopしてから) docker cp でコンテナが保持しているデータを抽出して、docker-compose.yml を編集しなおすのが良いと思います。

Minio

私は行っていないけど、参考までに。

nullkalさんのトゥート https://mstdn.jp/@nullkal/125745 によると「あ,一つ忠告なんですけど,どんなに小さい公開インスタンス作るとしてもMinioとか駆使して画像アセットだけはドメイン分けといたほうが後で人が多くなったときに楽です (二回目のリセットの理由はここです)」

Mastodonはユーザが投稿した画像などのデータをS3などのストレージサービスに保存する設定がある。ただし素直にS3を使ってしまうと費用的にバカ高いのでMinioなどのS3互換のストレージサーバを自分で建てることを推奨しているようだ。

最初にこれを行うことを勧めているのは、後から移行するのが困難だからだろう。

発生した問題

300人超で自宅鯖だと帯域の限界に

上り帯域が一日15GBを超えて、般家庭用のプロバイダ契約だと帯域規制の対象になりそうでした。一週間くらいでプロバイダから警告のメールやお手紙が届くので、そうなる前にVPSに移行することにしました。

  • 永続化が必要なボリュームには最初からホスト側のパスを指定していたのでそれ全部とmastodonのビルドツリーをtar cpjf で固めておく
  • 移動先のVPSで 同じフォルダ構成で展開する
  • docker-compose build && docker-compose up -d

で移行終了。

ここで下手にgit pull とか docker-compose run --rm web rails assets:precompile とかしちゃうとassets がうまくなくてWebアプリのJavaScriptがうまく動かなくなる。assetsこわい

Webアプリ用にプリコンパイルされるassetsを削除する方法は rails --tasks に2つ説明されています。

rails assets:clean[keep]                          # Remove old compiled assets
rails assets:clobber                              # Remove compiled assets

assets:clobberの方は「Errno::EBUSY: Resource busy @ dir_s_rmdir - /mastodon/public/assets」と怒られますが、削除するファイルはassets:cleanより多いです。

docker-compose run --rm web rails assets:clean
docker-compose run --rm web rails assets:clobber

のように両方を呼び出すと、public/assets/ には何もファイルがない状態になります。

800人超 で 帯域4Mbpsの限界に

だいたい4Mbpsあたりでクリップして帯域不足が発生しました。
VPSのお試し期間を切り上げて本登録したら 8Mbps前後でも安定するようになりました。

1100人超

今度はCPU負荷やディスク負荷が頭打ちになりました。
どのプロセスが重いのかdstat -tdng --file --lock --top-io --top-bio で調べてみたら sidekiq でした。
管理者メニューでsidekiqを見てみると待機中のpushキューが8kありました。

対策は https://medium.com/@Gargron/scaling-mastodon-1becde463090 に書いてあったものです。

  • 「ネイティブスレッドじゃないRubyだから、1プロセス複数スレッド => 複数プロセス複数スレッド に分けた方がより速い」
  • 「4種類のキューを並列にうごかすと良い。defaultキューが捌けるのが早いとユーザレスポンスが向上する」

sidekiqのpushは先方のサーバの処理速度に影響されるものだし、やや重いのは仕方ないですね

作業としては docker-compose.yml を編集してsidekiqのコンテナを増やしました。

記述例 https://gist.github.com/tateisu/646969c6281c9ef99c24a765cbd701ef

sidekiq -c に指定する並列数ですが、この時点ではメールキューとpullは5、defaultとpush は20程度で不足ありませんでした。

そしてこの並列数の最大値にあわせて、.env.production に DB_POOL=20 を指定します。
DB_POOL環境変数mastodon/config/database.yml で参照されています。
railsプロセス内のDBコネクションプールの数を指定するものです。
プロセスごとに最大でこの数までのDB接続を保持します。

設定ファイルを書き換えたら docker-compose down --remove-orphan とか docker compose up -d を行うと反映されます。
dockerコンテナのイメージを作成するのに10分前後かかりました。

溜まったキューはこれで消化されて、CPU使用率もディスク使用率も大幅に下がりました。

キューが溢れる原因は?

Mastodonの場合はどんなインスタンスと連動するか事前には分かりません。中には「とりあえず動かしてみたけどすぐ止めた」ような感じで稼働が安定しておらず、キューのジョブが接続タイムアウトで終わるようなインスタンスもあります。
基本的には処理プロセス数やスレッド数を増やして、いくつかブロッキングしても残りで十分に回せるようにするしかなさそうです。
手動で何かする余裕があるなら、管理者メニューのsidekiqで再試行や死亡を見てダメそうなのは削除するのも良いと思います。

アクティブユーザ500人超 ?

docker 公式の nginx イメージは worker_processes 1 と worker_connections 1024 が指定されています。
ストリーミングAPIを多数抱えるとこれでは足りなくなるので、適当に増やしましょう。
worker_processes 3 、worker_connections 20000 くらいにしました。

もし nginx環境でulimit -n して 低い数字が出るなら、worker_rlimit_nofile も指定する必要があるかもしれません。