小規模インスタンス向け　チューニングガイド

#はじめに
この記事は分散型SNSであるmastodonの[小規模インスタンス](https://mastodon.motcha.tech)(ほぼおひとり様状態）で
応答速度を高めるため、チューニングを行った記録です。
効果があったものについて、得た知識をまとめています。

#TL;DR
* DB：Pgbouncerによるコネクションプール/クエリキャッシュが有効
* Redis:マシン内の接続はTCP/IPではなくUNIX domain socketにして稼ぐ
* Web/Streamingは体感速度に直結するのでメモリを確保する → Sidekiqスレッドを増やしすぎないこと
* SidekiqはWebフロントエンドが稼働するマシンから切り離しても大丈夫

#環境(参考）
VPS：CloudGarage [1Core 1GB-RAM] x 3台
OS:Ubuntu 16.04

mastodon v2.3.1 (非Docker)
 - Postgresql-9.5
 - Redis-Server 2:3.0.6-1

![構成図(APP).png](https://qiita-image-store.s3.amazonaws.com/0/137968/5a3ebc57-cb62-b058-d0c7-a784cf10c0dd.png)
3台の仮想マシンが稼働しており、それぞれが役割を分担しています。
大まかに分類すると、自鯖の構成は
Web：フロント側でユーザからの接続を処理
db：必要となるデータの読み書き/バックグラウンド処理
minio:オブジェクトストレージ/メトリクス監視
となっています。

caddyはHTTPS化/証明書更新を自動でやってくれるお手軽なWebサーバです。
nginxの代わりに使っていますが、やっていることは同じです（リバースプロキシ）。
minioサーバの諸々については、今回のガイドでは無視してください。

まず、Mastodonを構成するソフトウェアについてざっとおさらいしましょう。
ポート番号はmastodon公式プロダクションガイドから変更していない場合の値です。

| 名前 | 役割 | ポート番号(TCP) |備考|
|:-:|:-:|:-:|:-:|
| nginx | webサーバ | 443/80 | リバースプロキシ|
| puma  | webサーバ |  3000 | 内部でサイト生成 |
|  ?(node.js) |  ストリーミング | 4000|TL更新|
| Sidekiq | バックグラウンドジョブ | ephemeral |-|
| Redis | NoSQLデータベース | 6379 |メモリで動作| 
| Postgresql | データベース |UNIX domain socket|-|


#mastodon-*.serviceのチューニング
Docker非利用の場合、web/sidekiq/streamingの3サービスが稼働します。
まずはこれらの設定から見ていきましょう。
※このセクションはほぼ[公式ガイド(英語)](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Tuning.md)からの抜粋/意訳です。

/etc/systemd/system/mastodon-*.serviceが設定ファイルです。
設定変更後は```sudo systemctl daemon-reload```してから
サービスを再起動すると反映されます。

##mastodon-web.service

以下の２つの値を設定できます。
WEB_CONCURRENCY ：　ワーカープロセス数
MAX_THREADS ：　プロセスごとのスレッド数

デフォルトでは2ワーカープロセス/５スレッドが稼働します。
同じ親プロセスを持つスレッド同士は、メモリを共有します。
各プロセスは各自のメモリ領域を確保しますが、
一部のメモリについては別のプロセスとCopy-on-Writeで共有します。

そのため、
プロセス数を増やす→RAM負荷が先行して高まる
スレッド数を増やす→CPU負荷が先行して高まる
こととなります。

これらの値は「どれだけ同時にHTTPリクエストを処理できるか」に影響します。
リクエストを処理できるスレッドがいない場合、応答が遅れます。

「おひとり様インスタンスでは、1プロセス/5スレッドもあれば十分」と
ガイドにも記載されているので、小規模インスタンスでは以下の設定から始めてみるといいでしょう。

```:/etc/systemd/system/mastodon-web.service
...
Environment="WEB_CONCURRENCY=1"
Environment="MAX_THREADS=5"
ExecStart="..."
...
```
アクセス数が多い時に応答が遅いなどあれば、状況に合わせて値を弄っていきましょう。

##mastodon-sidekiq.service
矢継ぎ早にやってくるHTTPリクエストに対して、実際の処理は時間がかかるものです。
そのため、非同期的にジョブを管理・実行するのがSidekiqの役割です。
特定のポートで待ち受けたりしないので、Postgresql(とRedis?)が見えていれば
どこでプロセスが動いていても問題ありません。

Sidekiqは「どれだけ早くTootが他のインスタンス/別のユーザに配送されるか」などなど、
バックグラウンドのジョブ処理速度に影響します。
ブラウザ上で感じる応答性はweb/streamingが直接影響するので、
メモリ状況を考えてSidekiqへの割り当てを決めましょう。
あまり割り当てすぎるとweb側がモッサリします。

Sidekiqはシングルプロセスで、設定できるのはスレッド数(デフォルトは5スレッド)です。
下記の-cオプションがスレッド数に該当します。

```:/etc/systemd/system/mastodon-sidekiq.service
bundle exec sidekiq -c 15 -q default -q mailers -q push -q pull
```
と書けば、15スレッドが稼働します。
web側を邪魔しない範疇で、他タンスへの配送が遅くなりすぎないよう調整しましょう。
ちなみにキューは以下のような役割を担当します。

| キュー | 用途 |
|:-:|:-:|
|  default |  大半のタスクが含まれる|
|  mailers | メール送信  |
|push|外部へのメッセージ配信|

また、各スレッドはDBに接続する必要があるため、
Sidekiqスレッドを増やすとDBコネクションが増えます。
コネクションプールは```DB_POOL```という環境変数で設定可能です。
特に設定しない場合はmastodon-web.serviceに記載した
```MAX_THREADS```の値が適用されます(デフォルトは5)。

もし```MAX_THREADS```と異なるスレッド数を動かす場合は
Sidekiq.serviceで```DB_POOL```を設定する必要があります。

```
...
[Service]
Type=simple
User=<USER NAME>
WorkingDirectory=/home/<USERNAME>/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=15"
ExecStart=/home/<USERNAME>/.rbenv/shims/bundle exec sidekiq -c 15 -q default -q push -q pull -q mailers
TimeoutSec=15
...
```

##mastodon-streaming.service
特にいじる必要ナシ。デフォで大丈夫です。

#DB
PgBouncerによるコネクションプールを行います。
手前味噌ですが、[こちら](https://qiita.com/motiakoron/items/9542f78d5c925c376aab)を参照してください。

#Redis
UNIXドメインソケットを利用して稼ぎます。
何それ？って人は[こちら](https://qiita.com/kuni-nakaji/items/d11219e4ad7c74ece748)を。
まずはRedisが稼働するdbサーバ上で設定変更

```:/etc/redis/redis.conf
...
# Specify the path for the Unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
unixsocket /var/run/redis/redis.sock
unixsocketperm 777
...
```
あとはRedisが稼働しているサーバだけ、
UNIXドメインソケットを利用するよう.env.productionを書き換えます。

```:.env.production
# Service dependencies
#REDIS_HOST=<Redis host IP address>
#REDIS_PORT=6379
REDIS_URL=unix:///var/run/redis/redis.sock
...
```
Redisとmastodon-*.serviceを再起動し、設定を反映します。

#まとめ
Mastodonが日本で流行し始めてからそこそこ経ちましたね。
たくさんのインスタンスが建ち、そして消えていきました。
サーバ管理はお金も時間もかかるため、個人運営だと断念する人も多いようです。
金銭的負担を考えると、高価な環境に手が出せない人も多いのではないでしょうか。

特にメモリがカツカツになりがちですが、そんな中でも
環境に沿った設定を入れてあげれば応答速度はグッと変わります。
快適なサーバにチューンしてあげると単純に使っていて不満が減りますし、
なにより自鯖に愛着も湧いてくるはずです。
~~Pleromaにすればいいじゃんとかそういうツッコミはナシで~~

ということで、当ガイドが快適なMastodonライフの一助になれば幸いです。
何か質問などあったら[@mot](https://mastodon.motcha.tech/@mot)へどうぞ。

#参考サイト
[公式ガイド(英語)](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Tuning.md)
[PgBouncer](https://pgbouncer.github.io/)