備忘録として残しておきます
Mastodon専用ユーザにて、Mastodonのインストールディレクトリにて操作することを前提にしています。
(非Dockerならlive
ディレクトリ)
重要なお知らせ
2022/1/11時点で他サイトへ移行したため、以後、本記事はメンテナンスされません。
経緯についてはこちら、移行後の記事はこちらです。
参考資料
他の記事、ウェブサイトへのリンク集
GitHubリポジトリ
公式ドキュメント
インストール手順
Installing from source - Mastodon documentation
公式ドキュメント。Ubuntuにインストールするならこの手順に従う。
Mastodon構築手順・非Docker版
非公式・手前味噌ドキュメント。RHEL系なら参考になるかも。
アップデート手順
Upgrading to a new release - Mastodon documentation
公式ドキュメント。非Docker。
Mastodonアップデート手順(基本)・非Docker版
非公式・手前味噌ドキュメント。内容としてはおおむね重複している。
バックアップ手順
Backing up your server - Mastodon documentation
公式ドキュメント。
サーバ移行手順
Migrating to a new machine - Mastodon documentation
公式ドキュメント。非Docker。
Mastodonサーバ移行手順(非Docker)
非公式・手前味噌ドキュメント。内容としてはおおむね重複している。
スパム対策
Mastodonにおけるスパム対策
非公式・手前味噌ドキュメント。内容が肥大化したため、別記事に分離しました。
サービス保守
tootctl
v2.5.0より、tootctl
という保守用コマンドラインツールが追加された。
Rakeタスクでの引数指定方法等への不満から誕生したものである。
既存Rakeタスクは、初期セットアップに使う一部のものを除き、tootctl
に置き換えられた。
tootctl周りについては、肥大化してしまったため勝手ながら別投稿に移動した。
なお、公式ドキュメントもある。
Using the admin CLI - Mastodon documentation
tootctl の実体
ここに入っているファイルたち。
Rakeタスク
主に初期セットアップに使用するコマンドラインツール。
v2.5.0以前は管理タスクも含まれていた。
あるいは
# すべてのRakeタスクを表示
$ RAILS_ENV=production bundle exec rails -T
# Namespace "mastodon" のタスクのみ表示
$ RAILS_ENV=production bundle exec rails -T mastodon
で、定義されているタスクが一覧(+簡単な説明文)表示される。
v2.6.1
で確認したところでは、殆どの管理タスクがtootctl
に移行されている。
タスク一覧の出力例
$ RAILS_ENV=production bundle exec rails -T mastodon
rails mastodon:setup # Configure the instance for production use
rails mastodon:stats # Report code statistics (KLOCs, etc)
rails mastodon:webpush:generate_vapid_key # Generate VAPID key
Rakeタスクの実体
tootctlやrakeタスクをcronで動かしたいとき
cronから直接実行すると、環境変数が読み込まれず動作しない模様
たとえば、毎日0時0分にmedia remove
を実行する場合は下記のようにする
0 0 * * * /bin/bash -l -c 'cd ~/live && RAILS_ENV=production bundle exec bin/tootctl media remove >> ~/log/media_remove.log 2>&1'
crontabでの時間指定の仕方については、ここでは省かせて頂く(検索するとたくさん出てくる)
これによりtootctl等のコマンドを通常通り実行することができる。
※Docker環境での動かし方について情報求む
irbを使った操作(tootctlやrakeタスクを介さない操作)
irb(Interactive Ruby Shell)
を用いれば、Mastodonの環境でRubyのコードを直接実行できる。
いろいろできるということは、それなりに危険を伴うのでオススメはできない。
irbの起動のしかた
非Docker
$ pwd
/home/mastodon/live
$ RAILS_ENV=production bundle exec rails console
irb(main):001:0>
Docker
$ docker-compose run --rm web rails console
irb(main):001:0>
※Docker環境がないため未検証
トラブルシューティング
不具合かな?と思ったときの切り分け方法など
まず落ち着いて!
-
Lv 1: 異常に重たいけど機能している
何かしらのバックグラウンドタスクでリソースを圧迫している可能性がある。
コンソール接続できる場合は、top
コマンド等で何がリソースを消費しているか調べる。
※一般的に、アクセス集中やフォローリストインポート、アーカイブ生成などで一時的に重くなることがある。 -
Lv 2: 象バンバン(HTTP 503)が出た
Mastodon関連サービスでエラーが発生している、もしくは記憶領域を使い果たした可能性がある。
コンソール接続できる場合は、ディスクの空き容量はあるか、Mastodon関連サービスが起動しているか、あるいは後述する「Mastodonサービスのログを見る」で何が原因か突き止める。 -
Lv 3: そもそもつながらない。ブラウザにエラーが出る。
証明書関連のエラーが出た(信頼できないサーバです、など)場合は、証明書の有効期限をチェックする。
接続タイムアウトの場合は、ネットワークは正常か・サーバが起動しているか・Nginxサービスが起動しているか・ファイアウォール設定は正しいか・DNS設定が正しいか、などを順番にチェックする。 -
番外編: アップデート後に不具合が出た
ログを確認するとともに、アップデート手順に抜けがないかチェックする。
リリースによっては、追加の作業が必要な場合もあるため。リリースノートを再度チェックする。
ハマりがちなところ:- データベースマイグレーション実行忘れ … システムが動作不良を起こす。mastodon-web のログに「column not found」などのエラーが出る。
- アセットコンパイル忘れ … 画面の動きがおかしくなったり、画像がリンク切れになったりする。必要に応じてclobberをしてからprecompileを実施する。
-
一時ディレクトリアクセス権の問題 … 画像のアップロードができなくなり、画面上に500エラーが出る。
nginxのエラーログに「access denied」といったエラーが出る。エラーが出ているディレクトリの所有者を nginx.confで指定したユーザーにする -
サブリソース整合性の問題 … 画面が真っ白になるなど、正常に描画されなくなる。ブラウザのコンソールに
Failed to find a valid digest in the 'integrity' attribute for resource ~
などといった警告が出る。配信経路上でリソース(JavaScript等)の改竄が検出されたことによる読み込み阻止が働いている。たとえばCloudflare等のCDNで「JavaScript等の最適化」といったオプションが有効になっている場合はオフにすることで改善される。
ログの見かた
非Docker環境です。
Docker環境での情報求む。
Mastodonサービス
$ sudo journalctl -r -u mastodon-web
$ sudo journalctl -r -u mastodon-sidekiq
$ sudo journalctl -r -u mastodon-streaming
-r
で新しいものを先に表示
-u
で表示するモジュールを指定
-f
も付ければ、継続監視が可能(tail
みたいに)
PostgreSQL
$ sudo journalctl -r -u postgresql
Nginx
$ sudo tail /var/log/nginx/access.log
$ sudo tail /var/log/nginx/error.log
継続して監視したい時は、 tail -f
が便利
よく使うやつのメモ:
$ sudo tail -f /var/log/nginx/access.log | grep -v " /inbox "
$ sudo tail -f /var/log/nginx/access.log | grep -v " (Mastodon/"
$ sudo cat /var/log/nginx/access.log | grep " 404 "
$ sudo tail -f /var/log/nginx/access.log | grep -E "[Bb]ot"
ディスクの空き容量を確保したいとき
連合経由でとめどなく情報が流れてきて蓄積していくので、何の対策もとっていないと、恐ろしい速度でディスク領域を食いつぶしていきます…
メディアファイル類のキャッシュ削除
メディアファイル(添付された画像・音声・動画)、プレビューカードのサムネイルなどのキャッシュファイル。
空き容量が逼迫している場合、真っ先に着手すべきはこれらのクリーンアップを行こと。
メディアファイルキャッシュ
外部のメディアファイルの削除には、tootctl
コマンドを用いる。
参考→ 勝手 Mastodon tootctl リファレンス - 外部サーバの古いメディアファイルを消す(remove)
外部のメディアファイルは再取得可能で、最悪発信元サーバを見に行けば問題ない。
また、自サーバのメディアファイルについては対象としない。
孤立メディアファイル
どこからもリンクされていない、孤立したメディアファイルを削除する。
参考→ 勝手 Mastodon tootctl リファレンス - どこからも参照されていないメディアを削除する (remove-orphans)
これは、ファイルシステムを走査してどこからも参照されていないメディアファイルを見つけ出し、削除するもの。
※オブジェクトストレージ等、ディスク操作に課金されている環境の場合、十分に検討した上で使用しすること。
プレビューカード
参考→ 勝手 Mastodon tootctl リファレンス - 古いプレビューカードを削除する(remove)
プレビューカードを消したところでリンクの動作に問題が起こるわけではない。
また、一定期間後に再度リンクが貼られた場合、再取得しに行くため、恒久的に生成されなくなるわけではない。
投稿キャッシュ
誰からもフォローされていないユーザの古い投稿を削除する。
参考→ 勝手 Mastodon tootctl リファレンス - 過去の投稿を削除する(remove)
参考資料のリンク先にも記載があるが、これを実行しただけではディスク使用領域を解放することができない。
VACUUM FULL
もしくはpg_repack
を実行すること。
存在しないユーザの削除
すでに存在しない外部ユーザを削除する。
参考→ 勝手 Mastodon tootctl リファレンス - 存在しないリモートユーザを削除する(cull)
アイコンやヘッダー画像のクリーンアップの意味合いが強いが、あまり効果的ではないように思う。
メディアファイルをオブジェクトストレージに逃がす
ある程度のコスト増を飲めるのであれば、メディアファイルをオブジェクトストレージに逃がすことで、ローカルの空き容量を大きく確保することができる。
参考1 → Mastodon docs - Configuring your environment - File storage
参考2 → MastodonのメディアファイルをOpenStack Swift互換オブジェクトストレージに移行する
オブジェクトストレージの課金システムについては様々なバリエーションがあるので、注意深く選定されたし。
Ruby Gem を再インストールしたいとき
稀に壊れたりすることがあるようです
$ bundle pristine
thanks @theoria !
あるいは
$ bundle exec gem uninstall -aIx
$ bundle install
引数 -aIx
で、「全てを確認無しでアンインストール」
その後、通常通りインストールする
bundler
経由で操作しないと、グローバル環境のGemに作用する?らしいので注意。
アセットをゼロから作り直したいとき
$ RAILS_ENV=production bundle exec rails assets:clobber
$ RAILS_ENV=production bundle exec rails assets:precompile
clobber
で webpackの出力を全消しできる。
長いことclobber
をしていないと、古いアセットが残りっぱなしになることがある(らしい)ので、たまにやった方がいいかもしれない。
パフォーマンスチューニング
(他にやれそうなことがあったら教えてください)
スワップファイルの作成
低スペックのサーバ、特にメモリが2GB未満のサーバで動作させていると
OOM Killer
(Out-Of-Memory Killer)によってbundler
などの重要なプロセスが強制終了されてしまうことがある。
ローカルディスクの空き容量に余裕がある環境であれば、スワップファイルを用意することでスワップメモリとして容量を拡張することができる。
# 2GBの /swapfile を作成する
$ sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
# ファイルをスワップ領域としてマークし、マウントする
$ sudo mkswap /swapfile
# スワップを一時的に有効にする
$ sudo swapon
# スワップファイルを永続化する
$ sudo vim /etc/fstab
/swapfile swap swap defaults 0 0
ただし、スワップファイルはメインメモリに比べると 圧倒的に遅い ため、できればメモリを2GB以上に拡張することをお勧めする。
PostgreSQL
サーバスペックに応じたパラメータを設定する
たとえば、pgTune( http://pgtune.leopard.in.ua/ )を参考に、サーバのスペックに合ったパラメータを設定する。
定期的にvacuumを行う
標準機能のautovacuum
を有効にしたり、cron等で定期的にvacuumdb
コマンドを実行する。
(環境によってはautovacuum
が無効になっているので要確認。postgresql.conf
に設定項目がある。)
それにより、データベースファイルの肥大化を防いだり、多少の速度アップが望めるかもしれない。
0 4 * * * /usr/bin/vacuumdb -z -U dbuser -d dbname >> ~/log/vacuum.log 2>&1
上記例では、毎日4時に権限のある全テーブルに対し、バキュームおよびオプティマイザ用統計情報の計算を行う。
テーブルロックがかからないとはいえ、それなりに負荷がかかることが想定されるので、アクティブな時間を外すとよい。
pg_repack
する
通常のvacuum
を定期的に行っても、テーブルサイズの肥大化を完全に抑えることはできない。
vacuum full
を実行すれば余計な領域を解放させることが可能だが、処理中はテーブルロックがかかってしまうため、実行中はサービス提供ができない。
それに対する解決策がpg_repack
である。
これは、最小限のロックでvacuum full
相当の操作をすることができるツール。
また、必要に応じてデータの並び替え(cluster
相当)も行うことが可能。
pg_repack
のインストール
事前に必要なモジュールをインストールし、pg_repackのビルドとインストールを行う。
$ sudo yum install rpm-build postgresql-devel postgresql-static
$ git clone https://github.com/reorg/pg_repack.git
$ cd pg_repack
$ make
$ sudo make install
データベース拡張としてpg_repackを登録する
$ sudo su - postgres
$ psql -c "CREATE EXTENSION pg_repack" -d mastodon
CREATE EXTENSION
$
pg_repack
の効果測定
現在のテーブル容量を見る
$ psql -d mastodon
mastodon# SELECT pg_size_pretty(pg_total_relation_size('statuses'));
pg_size_pretty
----------------
3041 MB
(1 行)
mastodon# \q
pg_repackを実行する
$ pg_repack -d mastodon -t statuses
実行後のテーブル容量を見る
$ psql -d mastodon
mastodon# SELECT pg_size_pretty(pg_total_relation_size('statuses'));
pg_size_pretty
----------------
26 MB
(1 行)
mastodon# \q
マジか
mastodon
データベース全体にpg_repack
を実行する
$ pg_repack mastodon
INFO: repacking table "public.account_aliases"
INFO: repacking table "public.account_conversations"
.
. (中略)
.
INFO: repacking table "public.web_push_subscriptions"
INFO: repacking table "public.web_settings"
$
vacuum full
相当の操作を行うものなので、タプルの追加削除が頻繁に行われるテーブルに対して行った方が効果が高い。(逆に、追加削除がほとんど行われていないテーブルに対して実行してもさして効果はない)
定期的に行うよりも、デッドタプルが増えてきたら実行する、くらいの感じがちょうどよいかもしれない。
PostgreSQLのvacuumについて調べたメモ - vacuumすべきか否かの判断
接続にSocketを使う
Unix Socketを使うことで、localhost接続よりも高速化が見込めるかもしれない。
listen_addresses = '' # TCP/IPでの待ち受けが必要ない場合は空白とする
unix_socket_directories = '/var/run/postgresql' # ソケットファイルの場所を指定する
デフォルトでは /tmp
をソケットディレクトリとして使用する。必要に応じて場所を変更する。
設定を変更したら、有効にするためPostgreSQLサービスを再起動する。
続いて、Mastodon側の設定も変更する。
DB_HOST=/var/run/postgresql
設定を変更したら、Mastodonサービス3点セットを再起動する。
pgBouncer を使う
PgBouncer とは
PgBouncer は、軽量なコネクションプーラーです。
通常、クライアントからデータベースに対して大量の接続が発生すると、接続を確立する為の時間のコストや、接続を管理する為のコンピュータリソースが多く必要となります。
このようなケースにおいて PgBouncer を使用すると、これらのコストを劇的に減少させる事ができます。
http://postgres.sios.com/modules/newbb/viewtopic.php?forum=1&topic_id=149&post_id=150
コネクションの開閉にはそこそこパワーを使うので、プールしておいて有効に使おうよ、という仕組み。
Mastodon公式ドキュメントにも、pgBouncerに関する記事がある。
Mastodon documentation - Scaling up your server - Transaction pooling with pgBouncer
Redis
Socketを使う
PostgreSQLと同様、Unix Socketを使うことで、localhost接続よりも高速化が見込めるかもしれない。
port 0 # TCP/IPでの待ち受けが必要ない場合はゼロとする
unixsocket /var/run/redis/redis.sock
unixsocketperm 777
デフォルトではソケットを使用しない設定になっているので、既存の設定値を消すかコメントアウトした上、ソケットの設定を追加する。
設定を変更したら、Redisサービスを再起動する。
続いて、Mastodon側の設定も変更する。
REDIS_URL=unix:///var/run/redis/redis.sock
#REDIS_HOST=127.0.0.1
#REDIS_PORT=6379
#REDIS_PASSWORD=
ソケットはREDIS_HOST
でなくREDIS_URL
に対して設定する点に注意!
設定を変更したら、Mastodonサービス3点セットを再起動する。
Mastodon
Tuning Mastodon (リンク切れ)
jemalloc
を使ってメモリ最適化
jemallocとは?
jemalloc は、標準ライブラリで定義されているmalloc, free 等のメモリアロケーション APIの実装である。
http://zonomasa.hatenablog.com/entry/jemalloc_about
詳しい機能については引用元のWebページを参考にして頂きたいが、わたしのざっくりとした理解では:
- メモリのフラグメンテーションを防止し、有効に使われるようにする
- マルチコア・スレッド環境においてパフォーマンス向上
- メモリ周りの不具合(リーク、オーバーフロー等)の検査ツール付
また、このパッケージについて公式ドキュメントでも紹介されている。
Tuning Mastodon - Using jemalloc
Debian系(Ubuntu等)においては、上記公式ドキュメント通りに設定すればよいが、Fedoraにおいてはパッケージ名等が違うので注意が必要。
- パッケージ名:
jemalloc
(jemalloc-5.0.1-5.fc28.x86_64
等) - インストールパス:
/usr/lib64/libjemalloc.so.2
jemallocの導入
$ sudo yum install jemalloc jemalloc-devel
$ ls /usr/lib64/libjemalloc.so.2
/usr/lib64/libjemalloc.so.2
Mastodonに対して設定する前に、Rubyをjemalloc
に対応させておく必要がある。
jemalloc
対応版かどうかを確認し、対応していない場合はRubyの再インストールが必要となる。
確認・アンインストール・インストール手順についての参考資料: rbenvでインストールしたRubyのバージョンを上げる
Mastodonサービス側の設定:jemallocの有効化
mastodon-web.service
および mastodon-sidekiq.service
に対し、
jemallocを読み込ませるため Environment="LD_PRELOAD=/usr/lib64/libjemalloc.so.2"
を追記する。
(下記はwebの例だが、sidekiqも同じように追記する。)
[Unit]
Description=mastodon-web
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3000"
Environment="LD_PRELOAD=/usr/lib64/libjemalloc.so.2"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
ExecReload=/bin/kill -SIGUSR1 $MAINPID
TimeoutSec=15
Restart=always
[Install]
WantedBy=multi-user.target
編集後、更新されたファイルを再読み込みし、webとsidekiqを再起動する。
$ sudo systemctl daemon-reload
$ sudo systemctl restart mastodon-{web,sidekiq}
あまり知られていないであろう設定項目
おもに .env.production
にて設定する項目たちです
セキュア(Authorized Fetch)モード
インライン署名されたアクティビティを拒否し、他サーバが公開・非収載の投稿を取得しようとするときに認証を必須とする。
それにより、ブロックしているサーバが投稿を取得していくことを防ぐことができる。(完全に防ぐことを保証するものではない)
ただし、計算コストが上がり、古いバージョンと互換性がなくなる(たとえばMastodon v3.0以前)、連合リレーに参加できなくなる、など制限が発生する。
設定方法
Step 1: .env.production
ファイルに、Authorized Fetchモードを有効にする一文を追記する。
AUTHORIZED_FETCH=true
Step 2: Mastodonサービスを再起動する。
連合制限モード
どのバージョンからなのかは不明だが、ホワイトリストモードが追加された。
これは、 特定のサーバと対してのみ やりとりをできるようにするモードである。
v3.2.0より、「連合制限モード(limited federation mode)」と名前が改められた。
連合制限モードの特徴
- 許可リストに登録しているサーバ相手なら、普段通りやりとりができる。
- 途中で連合許可モードに切り替えた場合、許可リストに登録していないサーバを一括パージできるコマンドがある(
tootctl domain purge --limited-federation-mode
) → 参考資料 - 非ログイン状態では、ほとんどのパブリックページへのアクセスができなくなる。
-
/about
、/about/more
、/pubiuc
、/@username
(ユーザの個別ページ) 等へのアクセスは、ログイン画面にリダイレクトされる。 - API経由でも同様。
/api/v1/insances
、/api/v1/accounts/:id
等へのアクセスにはログインが必要となる。 - 許可リストにないサーバからでもアカウント名を決め打ちで検索すれば、アカウントの存在を知ることはできる。
- 許可リストにないサーバからの接触(フォロー、リプライ等)は弾かれると思われる。(未検証)
設定方法
Step 1: .env.production
ファイルに、連合許可モードを有効にする一文を追記する。
# v3.1.5まで
WHITELIST_MODE=true
# v3.2.0rcから
LIMITED_FEDERATION_MODE=true
Step 2: Mastodonサービスを再起動する。
Step 3: 管理者でログインし、設定画面の [管理] → [既知のサーバー] ページを開き、[連合を許可]より許可リストへ追加を行う。
Step 4: 許可リストにないサーバーを切り離す
$ sudo su - mastodon
$ RAILS_ENV=production bundle exec bin/tootctl domains purge --limited-federation-mode
その他小ネタなど
- ホスティングサービス等を使用せず、独自にサーバを立て、収益を上げるような仕組み(広告、アフィリエイト、寄付など)を設け、自分以外の第三者にも使用できる状態にした場合、各地域の総合通信局に「電気通信事業届出」が必要となります。(未届で行った場合、一応罰則もあるようです)
- 「サイト設定」内に連絡先を記載。メールアドレス、管理者欄を埋める。他のサーバのアカウントなどがあれば併記しておく。サーバに何かあったときに、誰かが知らせてくれるかも。
「お知らせ」の時差(JST to UTC)
タイムラインの上に出る「お知らせ」を作成する際、日付時刻の範囲や掲載開始日時を設定できるが
これはJST(日本標準時)でなくUTC(協定世界時)で設定しなければならない。
UTC・JST間の時差は +9 時間である。
つまり、日本標準時で昼の12時を指定したい場合は、協定世界時の早朝3時にセットする必要がある。
時差を計算するサイトも多数あるので、それらを使うと楽。
アーカイブファイルの読み方
Mastodonの「 設定 > インポート・エクスポート > アーカイブのリクエスト
」を用いると、自分が投稿した文章や画像をまとめてダウンロードできるようになります。
しかし、内容はActivityPub
形式の大きなJSONファイルのため、そのまま読める形にはなっていません。
手前味噌ですが、ActivityPub
形式のoutbox.json
を読める簡易リーダーを試作しました。
https://gist.github.com/Neustrashimy/51442fe6932c86d2555e18bada0d6c93
使い方は下記投稿を参考にしてください。
https://md.objektiv2.net/@kumasun/103099863276308470
全文検索に対応していないサーバでも、この方法であればブラウザのテキスト検索機能を使用して検索することができます。
謎のファイルが /tmp
を食いつぶす問題
/tmp/magick-*
(ImageMagickの一時ファイル)
Mastodon側で画像の縮小・メタ情報削除を行う処理を行うようになっているため、そのような一時ファイルが生成されます。
また、何らかの原因により、一時ファイルが削除されず残ってしまうことがあるようです。
/tmp
は様々なアプリケーションが一時ファイル置き場として使うので、使い切ってしまうとサーバごと機能不全に陥る可能性があります。
応急処置としては、手動で一時ファイルを削除することで解消できます。
$ rm /tmp/magick-*
再発する場合は、ImageMagickが使用するディスク領域を制限することで解消を図ります。
$ identify -list resource
Resource limits:
Width: 214.7MP
Height: 214.7MP
List length: unlimited
Area: 2.0403GP
Memory: 972.867MiB
Map: 1.90013GiB
Disk: unlimited
File: 768
Thread: 2
Throttle: 0
Time: unlimited
Disk: unlimited
になっているため、限界まで使用しようとします。これを制限します。
$ sudo vim /etc/ImageMagick-6/policy.xml
<policymap>
<policy domain="resource" name="disk" value="256MB"/>
</policymap>
<policymap>
以下にコメントアウトされている設定値が羅列してありますので、該当部分をコメントアウトして設定し、保存します
$ identify -list resource
Resource limits:
Width: 214.7MP
Height: 214.7MP
List length: unlimited
Area: 2.0403GP
Memory: 972.867MiB
Map: 1.90013GiB
Disk: 256000000B
File: 768
Thread: 2
Throttle: 0
Time: unlimited
Disk値が制限されました。
とりあえず、これで様子を見てみます。
Paperclipの一時ファイル(v3.1.4)
$ ll /tmp
total 138992
-rw------- 1 mastodon mastodon 388526 May 21 13:21 8d777f385d3dfec8815d20f7496026dc20200521-41299-100pphy
-rw------- 1 mastodon mastodon 201603 May 21 13:21 8d777f385d3dfec8815d20f7496026dc20200521-41299-102g7ck
-rw------- 1 mastodon mastodon 106475 May 21 13:21 8d777f385d3dfec8815d20f7496026dc20200521-41299-1052yfm
-rw------- 1 mastodon mastodon 41792 May 21 13:21 8d777f385d3dfec8815d20f7496026dc20200521-41299-10g2myt
-rw------- 1 mastodon mastodon 54901 May 21 13:21 8d777f385d3dfec8815d20f7496026dc20200521-41299-10indac
-rw------- 1 mastodon mastodon 26021 May 21 13:21 8d777f385d3dfec8815d20f7496026dc20200521-41299-10rv5ny
-rw------- 1 mastodon mastodon 416685 May 21 13:21 8d777f385d3dfec8815d20f7496026dc20200521-41299-10ytz90
-rw------- 1 mastodon mastodon 23994 May 21 13:21 8d777f385d3dfec8815d20f7496026dc20200521-41299-116kyt4
-rw------- 1 mastodon mastodon 9726 May 21 13:21 8d777f385d3dfec8815d20f7496026dc20200521-41299-11d09gv
- 先頭の文字列(
8d777f385d3dfec8815d20f7496026dc20200521
)はSidekiqのJID - 数字(
41299
)は、mastodon-sidekiq
のプロセスID - 末尾の文字列(
11d09gv
等)はSidekiqのTID
であり、Paperclip(ファイル等を操作するライブラリ)によって生成された一時ファイルだろうと思われる。
Sidekiqの管理画面上で該当するジョブが走っていなければ、おそらく消し忘れなので、手動で消しても差し支えないように思う。
PostgreSQL照合順序によるインデックスの不整合
2018年頃、PostgreSQLデータベースの照合順序として使われているglibc
のロケールデータが更新された。
その結果、本来一意になるはずのインデックスの重複判定がうまくされないことによって、データが重複してしまう可能性がある。
glibc 2.2.8
以前でインデックスを作り、それ以降のバージョンでインデックスの再作成をしていない場合、影響を受ける可能性がある。
# rpmコマンドで
$ rpm -q glibc
glibc-2.31-4.fc32.x86_64
# またはdnf、yumなどのパッケージマネージャで
$ dnf list installed | grep glibc
glibc.x86_64 2.31-4.fc32 @updates
glibc-common.x86_64 2.31-4.fc32 @updates
glibc-devel.x86_64 2.31-4.fc32 @updates
glibc-headers.x86_64 2.31-4.fc32 @updates
glibc-langpack-en.x86_64 2.31-4.fc32 @updates
自分の環境が影響を受けているのかチェック
Mastodonデータベースの照合順序をチェックし、影響を受ける可能性があるか見る。
ディストリビューションによって影響を受ける照合順序が異なるようなので、各自 PostgreSQL公式サイトの情報 を参照し、判断を行うこと。
$ psql -c "SELECT datcollate FROM pg_database WHERE datname=current_database()" -d mastodon
datcollate
-------------
en_US.UTF-8
(1 row)
以下の情報は、PostgreSQL公式Wikiの情報を和訳したものです。(20201230版)
最新ではなく、誤訳の可能性があるので、できれば ソース を読んでください。
Debian
Version 8 (jessie) と 9 (stretch)は古いロケールデータを使っています。それらのリリースでは互換性のない変更は確認されていません。Version 8 から 9 へのアップグレードは安全です。
Version 10 (buster) は新しいロケールデータを使っています。そのため、アップグレード時に注意が必要です。
以下の情報も参照してください:
https://lists.debian.org/debian-glibc/2019/03/msg00030.html
Ubuntu
Ubuntuは Version 18.04 (bionic) まで古いロケールデータを使っています。
新しい glibc 2.28 ロケールデータは (LTS版でない) Version 18.10 (cosmic) で登場しました。
bionicもしくはそれ以前から、cosmicより新しいバージョンへのアップグレードを行う際は、緩和手段が必要です。
RHEL/CentOS
バージョン 6 と 7 は古いロケールデータを使っています。バージョン 6 から 7 へのアップグレードは安全ですが、 de_DE.UTF-8
ロケールが使用されていた場合は別です。(その他のロケール、およびde_DE.UTF-8
を除くde_*.UTF-8
ロケール、たとえば de_AT
などは安全です。)
Version 8 は新しいロケールデータを使っています。そのため、アップグレードする際は注意が必要です。
実際にインデックスが壊れているのかチェック
Mastodon公式サイトでは、PostgreSQLのamcheck
拡張によるチェック方法が載っている。
amcheck
拡張はpostgresql-contrib
パッケージに含まれているので、事前にそれをインストールしておく。
amcheck拡張について、詳しくは下記ページを参照されたし。
PostgreSQL 10.5文書 - 付録F 追加で提供されるモジュール - F.2. amcheck
$ sudo dnf install postgresql-contrib
$ psql -c "CREATE EXTENSION IF NOT EXISTS amcheck" -d mastodon
CREATE EXTENSION
$ psql -d mastodon
psql (12.4)
Type "help" for help.
下記SQLは、どのリレーションが影響を受けたのか分かりやすくするためc.relname
を表示するようにしているが、それ以外はMastodon公式情報と全く同じ。
SELECT c.relname, bt_index_check(c.oid)
FROM pg_index i
JOIN pg_class c ON i.indexrelid = c.oid
WHERE c.relname IN ('index_account_domain_blocks_on_account_id_and_domain',
'index_account_proofs_on_account_and_provider_and_username',
'index_accounts_on_username_and_domain_lower', 'index_accounts_on_uri',
'index_accounts_on_url', 'index_conversations_on_uri',
'index_custom_emoji_categories_on_name',
'index_custom_emojis_on_shortcode_and_domain',
'index_devices_on_access_token_id', 'index_domain_allows_on_domain',
'index_domain_blocks_on_domain', 'index_email_domain_blocks_on_domain',
'index_invites_on_code', 'index_markers_on_user_id_and_timeline',
'index_media_attachments_on_shortcode', 'index_preview_cards_on_url',
'index_statuses_on_uri', 'index_tags_on_name_lower',
'index_tombstones_on_uri', 'index_unavailable_domains_on_domain',
'index_users_on_email', 'index_webauthn_credentials_on_external_id'
);
relname | bt_index_check
-----------------------------------------------------------+----------------
index_accounts_on_username_and_domain_lower |
index_users_on_email |
index_account_domain_blocks_on_account_id_and_domain |
index_account_proofs_on_account_and_provider_and_username |
index_devices_on_access_token_id |
index_invites_on_code |
index_conversations_on_uri |
index_custom_emojis_on_shortcode_and_domain |
index_accounts_on_uri |
index_accounts_on_url |
index_custom_emoji_categories_on_name |
index_domain_allows_on_domain |
index_domain_blocks_on_domain |
index_unavailable_domains_on_domain |
index_markers_on_user_id_and_timeline |
index_email_domain_blocks_on_domain |
index_media_attachments_on_shortcode |
index_preview_cards_on_url |
index_tombstones_on_uri |
index_statuses_on_uri |
index_tags_on_name_lower |
index_webauthn_credentials_on_external_id |
(22 rows)
bt_index_check
の列が空白であれば影響を受けている可能性は小さい。
逆に何かしらメッセージが出た場合は影響を受けている可能性がある。
メッセージが出なかった場合、さらに深く(親子関係も含めた)チェックを行うことが推奨されている。
このチェックはShareLock
を要求するため、実行中はデータベースへの書き込みができなくなるので注意。
SELECT c.relname, bt_index_parent_check(c.oid)
FROM pg_index i
JOIN pg_class c ON i.indexrelid = c.oid
WHERE c.relname IN ('index_account_domain_blocks_on_account_id_and_domain',
'index_account_proofs_on_account_and_provider_and_username',
'index_accounts_on_username_and_domain_lower', 'index_accounts_on_uri',
'index_accounts_on_url', 'index_conversations_on_uri',
'index_custom_emoji_categories_on_name',
'index_custom_emojis_on_shortcode_and_domain',
'index_devices_on_access_token_id', 'index_domain_allows_on_domain',
'index_domain_blocks_on_domain', 'index_email_domain_blocks_on_domain',
'index_invites_on_code', 'index_markers_on_user_id_and_timeline',
'index_media_attachments_on_shortcode', 'index_preview_cards_on_url',
'index_statuses_on_uri', 'index_tags_on_name_lower',
'index_tombstones_on_uri', 'index_unavailable_domains_on_domain',
'index_users_on_email', 'index_webauthn_credentials_on_external_id'
);
relname | bt_index_check
-----------------------------------------------------------+----------------
index_accounts_on_username_and_domain_lower |
index_users_on_email |
index_account_domain_blocks_on_account_id_and_domain |
index_account_proofs_on_account_and_provider_and_username |
index_devices_on_access_token_id |
index_invites_on_code |
index_conversations_on_uri |
index_custom_emojis_on_shortcode_and_domain |
index_accounts_on_uri |
index_accounts_on_url |
index_custom_emoji_categories_on_name |
index_domain_allows_on_domain |
index_domain_blocks_on_domain |
index_unavailable_domains_on_domain |
index_markers_on_user_id_and_timeline |
index_email_domain_blocks_on_domain |
index_media_attachments_on_shortcode |
index_preview_cards_on_url |
index_tombstones_on_uri |
index_statuses_on_uri |
index_tags_on_name_lower |
index_webauthn_credentials_on_external_id |
(22 rows)
bt_index_parent_check
の列が空白であれば問題ないため、db:migrate
時に出るメッセージを無視することができる。
影響を受けてしまっているようですが、どうすればいいですか?
修正するためのタスクが用意されているので安心してください!
RAILS_ENV=production tootctl maintenance fix-duplicates
このコマンドを実行することにより、各テーブルのインデックスを一時解除し、重複データの確認と削除を行ったのち、再度インデックスを張り直すという一連の操作を行うことができる。
手前味噌ですが以下の記事にも少し情報があるので参考にされたい。
勝手 Mastodon tootctl リファレンス - メンテナンスタスク系\重複データをマージ・削除する
この問題を回避するには?
libc
がアップデートされた際、ただちにインデックスの再作成を行うこと。
Mastodonサーバの閉じ方
tootctl self-distruct
というコマンドができています。
参考 → 勝手 tootctl リファレンス - サーバを連合から切り離す(self-destruct)
これを実行し、sidekiqキューを流しきった後、サーバを閉じるとよいかと思います。
無条件に「410 Gone」を返すことについて
過去記事(削除済み)にて「無条件に`410 Gone`を返すといいのではないか」という提言をしましたが、それだけではあまり意味がありませんでした。 繋がっていたサーバ側で`tootctl accounts cull`を実行した際、`410 Gone`が返ってこればそのアカウントは削除されたものとされ、繋がっていたサーバからも消されるはずです。 結果的に「そのサーバに属しているユーザがゼロ名」になることによって、投稿等の配信が行われなくなるのでは、という推測に基づいたものでした。 閉じたサーバが`410 Gone`を返していたとしても、繋がっているサーバが`tootctl account cull`もしくは`tootctl domains purge`をしない限り残り続けてしまい、 いつかサーバそのものが消え、名前が引けなくなったりタイムアウトを起こしたりした際に、またSidekiqの再試行キューに上がってきてしまいます。あとがき
- 自分用にメモした内容です。必要に応じて読み替えてください。
- 使用は自己責任でお願いします。何か不具合が起こっても責任取れません。
- こうしたほうがいいよ的なアドバイス、誤記や記載漏れ、動作の違い等の指摘を頂けると大変助かります。
- 連絡先: Mastodon1, Mastodon2
以上