Mastodon管理者のためのレプリケーション
レプリケーションのススメ
Mastodonサーバ管理者(鯖缶)のみなさん、レプリケーションしてますか?
ざっくり言うと、
- 元のPostgreSQLの設定にレプリケーションに必要な設定項目を追加する
- レプリケーション用のユーザーを作って、外から繋げられるように許可する
- レプリケーション先のサーバで、
pg_basebackup
でデータベースをコピーする - レプリケーション先のサーバを起動すると、同期を開始する(完了!)
という感じです。簡単でしょ?
何をしているか
- PostgreSQLは、データベースファイルに対する変更を実際に反映する前に、WAL(Write Ahead Logging)という変更内容のログを書き出している
- この仕組みにより、突然クラッシュした場合でも、データベースを正しい状態に保ちながら、安全に変更を反映して再開できる
- ある時点のデータベースファイルを保存しておいて、そこにWALを順次適用していけば、最新のデータベースを再現できる
- レプリケーションでは、WALをマスターからスタンバイに転送して、それをスタンバイ側で適用することで、同一のデータベースの複製を作っている
- 通常のWALだとレプリケーションに必要な情報が足りないので、少し内容を充実させたWALを書き出すように変更が必要
- スタンバイの最初のデータベースの複製は
pg_basebackup
でネットワーク越しに簡単にできる。recovery.conf
も自動的に作成される - スタンバイは、
recovery.conf
の指示にしたがって、リカバリをし続けている状態 - そのときが来たら、レプリケーションを終了して、こちらを本番サーバ(マスター)に昇格できる
pg_ctl promote
- WALをアーカイブしておくことで、任意の時点を再現(復元)することができる。別の場所に保存するとより強固になる
参考:WAL-GでオブジェクトストレージにPostgreSQLをバックアップしよう
メリット
- 待機(スタンバイ)サーバが実現でき、データベースサーバにトラブルがあった際に最短時間でサービスを復旧できる
- サーバを移転する際も、ギリギリまでサービスを継続しておいて、安全に最短時間で切り替えができる
- スタンバイに対して、参照のみのアクセスが可能なので、書き込みの不要なアクセスをそちらに振り向けることで負荷分散が可能
- mastodon-streaming(タイムラインのリアルタイム更新通知)は、読み取りだけでOK
設定手順
postgresql.confに設定する
listen_addresses
はpg_hba.cond
でアクセス制限を行う前提で*
に設定しているが、localhost,xxx.xxx.xxx.xxx
などと具体的に書いても良いhot_standby = on
はレプリケーション先に行う設定だが、後ほどpg_basebackup
する際にコピーされて有効になるのでここに書いておくと楽
# for replication master server listen_addresses = '*' synchronous_commit = off wal_level = replica max_wal_senders = 3 # for replication standby server hot_standby = on
replication_userを作る
パスワードを決めて、わかるようにしておくこと
sudo -u postgres psql -c "CREATE ROLE replication_user LOGIN REPLICATION PASSWORD 'xxxxxxxxx'";
(xxxxxxxxxの部分にパスワードを指定)
pg_hba.confに追記
host replication replication_user xxx.xxx.xxx.xxx/32 md5 host replication replication_user xxxx:xxxx::xxxx/128 md5
(xxx.xxx.xxx.xxxの部分にレプリケーション先のサーバのIPv4アドレスを指定) (xxxx:xxxx::xxxxの部分にレプリケーション先のサーバのIPv6アドレスを指定)
ここで一度PostgreSQLを再起動する。
sudo -u postgres pg_ctl restart
ファイアウォールで接続を許可
PostgreSQLのポートに、レプリケーション先のサーバから接続できるように許可する。ここでは5432で実行しているものと仮定する。
firewall-cmd
とufw
の例をあげておく。
firewall-cmd
firewall-cmd --zone=public --add-rich-rule='rule family=ipv4 source address=xxx.xxx.xxx.xxx/32 port port=5432 protocol=tcp accept' --permanent firewall-cmd --zone=public --add-rich-rule='rule family=ipv6 source address=xxxx:xxxx::xxxx/128 port port=5432 protocol=tcp accept' --permanent firewall-cmd --reload
ufw
ufw allow from xxx.xxx.xxx.xxx to any port 5432 proto tcp ufw allow from xxxx:xxxx::xxxx to any port 5432 proto tcp
空のクラスタを作成しておく
レプリケーション先となるサーバで、PostgreSQLをインストールして、データディレクトリを空にしておく。PostgreSQLは同じバージョンを使用すること。(違うバージョンでレプリケーションする方法もあるが、ここでは説明しない)
だいたい/var/lib/pgsql/9.2/data
とか/var/lib/postgresql/11/main
とか。
今回の目的以外でPostgreSQLを使っていないなら、実行を止めて、削除を行う。 既に利用中の場合は、新しいクラスタを作成すること。
sudo -u postgres pg_ctl stop sudo -u postgres rm -rf /var/lib/postgresql/11/main
pg_basebackupでまるごと複製してくる
レプリケーション先となるサーバから実行。
ここでの xxx.xxx.xxx.xxx はマスターのIPアドレス
umask 0077 sudo -u postgres pg_basebackup -h xxx.xxx.xxx.xxx -D /var/lib/postgresql/11/main -U replication_user -R -P umask 0002
設定に問題がなければ、接続して複製が開始される。
5432でサービスを実行していないなどと言われる場合は、pg_hba.confの設定、ファイアウォールの設定などで、マスターに接続できる条件が整っていない。
postgresql.confに設定する
レプリケーション先となるサーバのpostgresql.conf
にホットスタンバイの設定を追記する。
Debian / Ubuntu などではデータディレクトリ内のpostgresql.conf
ではなく/etc/postgresql/11/main/postgresql.conf
(ディレクトリ名はバージョンとクラスタ名による)が使われるので、ホットスタンバイに限らず、必要な設定は移行しておくこと。
# for replication standby server hot_standby = on
ついでにpg_hba.confも見直しておく
前項のようにデータディレクトリの中のpg_hba.conf
を読み込むとは限らない。/etc/postgresql/〜
の場合はそちらにコピーして今後はそちらで管理するようにするか、下記を参照して設定し直すこと。
ここでは、サーバ移転(引っ越し)や、待機サーバを本番に昇格することを想定し、Mastodonの実行に必要な設定と、マスターとしてレプリケーションを受け付けるための設定を合わせて記載している。
なお、データベース名はmastodon_production
としているが、Mastodonの設置が初期の頃の場合はmastodon
だったりするので、/home/mastodon/live/.env.production
のDB_NAME
を参照するなどして自分の環境に合わせて設定すること。
- postgresユーザーがソケットにより接続した場合だけ色々変更できるようにする。外部からは許可しない
- mastodonユーザーがローカルのTCP接続でパスワード認証した場合にだけ、mastodon_productionデータベースへ接続を許可する
- replication_userがレプリケーション先のサーバからTCP接続でパスワード認証した場合にだけ、レプリケーション(同期とかバックアップ)を許可する
- 初期設定はゆるゆるなので、できるだけ厳しく設定して、必要なものだけ許可する
- TYPE
local
はソケット接続なので、同一マシンからの接続専用 - TYPE
host
はTCP接続になるので、接続元のIPアドレス指定次第で外部からも接続できる- 同一マシンからの接続(loalhost)は、IPv4では
127.0.0.1/32
、IPv6では::1/128
と書く
- 同一マシンからの接続(loalhost)は、IPv4では
- METHOD
peer
にすると、ログインしているUNIXユーザーとPostgreSQLユーザーが一致すれば認証する - METHOD
md5
では指定したユーザーを(md5でハッシュにした)パスワードで認証する - METHOD
trust
は誰でも信用して全部許可しちゃうので論外
- TYPE
# TYPE DATABASE USER ADDRESS METHOD local all postgres peer host mastodon_production mastodon 127.0.0.1/32 md5 host mastodon_production mastodon ::1/128 md5 host replication replication_user xxx.xxx.xxx.xxx/32 md5 host replication replication_user xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/128 md5 _EOS_
レプリケーション先のサーバを起動する
ここまで来たら、あとは起動するだけで完了。自動的にrecovery.conf
に基づいて、マスターからWALを受け取り、レプリケーションを開始する。
sudo -u postgres pg_ctl start
本番サーバに切り替える
障害の時は不要だが、マスターがまだ動いている場合は停止する。
マスターと同期の完了したスタンバイを、本番サーバに切り替える。
sudo -u postgres pg_ctl promote
切り替えが完了すると、recovery.conf
がrecovery.done
にリネームされる。
余談
- pg_basebackupが優秀なので、コイツを使って、手元のマシンにバックアップだけとるという手もある。
- レプリケーションは複数ぶら下げたり、多段にカスケードすることもできる。
- 今回、スタンバイの更新を待って動作する同期レプリケーション、待たない非同期、WALがシンクロするのを待つか、など細かい設定については省略したので、各自で調べられたし。
- バージョン違いでレプリケーションしたい場合は、ロジカルレプリケーションという方法がある。