お疲れ様!今日も元気にPostgreSQLと格闘してるかい?
さて、今日はPostgreSQLの運用でめちゃくちゃ重要なのに、意外と「なんとなく使ってる」って人も多いんじゃないかと思う機能、「レプリケーションスロット」について、現場の視点からじっくり解説していくよ。
ぶっちゃけ、これがないと安定したレプリケーションは難しいし、いざという時に痛い目を見ることも少なくない。だから、しっかりとその役割と使い方、そして注意点を押さえておこうね。
—
レプリケーションスロットって、結局何? WAL削除の番人だよ!
まずは、レプリケーションスロットが何のためにあるのか、その大前提から話そうか。
PostgreSQLでレプリケーションを組むとき、プライマリ(マスター)側で生成される「WAL(Write Ahead Log)」がスタンバイ(スレーブ)側に送られて、データの同期が図られるよね。このWALファイルって、データベースの変更履歴そのものだから、非常に重要なファイルなんだ。
プライマリ側では、ディスク容量を圧迫しないように、一定期間が経過したり、特定のチェックポイントを超えたりすると、古いWALファイルを削除していくのが標準的な挙動なんだ。
でも、ここに落とし穴がある。
もしスタンバイ側が何らかの理由で遅延したり、一時的に停止したりした場合、プライマリが「もうこのWALファイルは古くなったから消していいな」と判断して削除しちゃったらどうなると思う?
そう、スタンバイ側は必要なWALファイルを受け取れなくなって、レプリケーションが追従できなくなり、最悪の場合、手動でベースバックアップを取り直す羽目になるんだ。これ、結構な手間だし、サービス停止を伴う可能性もあるから、できるだけ避けたい事態だよね。
そこで登場するのが、このレプリケーションスロットってわけ。
レプリケーションスロットは、一言で言えば「特定のスタンバイがまだ処理していないWALファイルを、プライマリ側で削除されないように保持しておく仕組み」なんだ。
例えるなら、スタンバイが「ごめん、まだ読んでないからこの本捨てないで!」ってプライマリに伝えて、プライマリがそれをしっかり覚えておいてくれる、そんなイメージだね。
物理スロットと論理スロット
レプリケーションスロットには、「物理スロット」と「論理スロット」の2種類があるんだけど、今日の話は主に物理レプリケーション(ストリーミングレプリケーションとか)で使う「物理スロット」に焦点を当てるよ。
論理スロットは、特定のアプリケーションや外部システムにデータを連携させたり、異なるバージョンのPostgreSQL間でレプリケーションを組んだりする、もっと高度な用途で使うものだと思っておけばOKだ。これはまた別の機会にじっくり話そう。
—
なぜレプリケーションスロットが必要なの? 具体的な課題を解消しよう
「WALを保持する」ってだけ聞くと、`wal_keep_size`とか`archive_command`とかでもできるじゃん、って思う人もいるかもしれないね。もちろんそれらも大事な設定なんだけど、レプリケーションスロットにはそれらを凌駕するメリットがあるんだ。
`wal_keep_size`の限界と「WAL file has been removed」の恐怖
`wal_keep_size`は、プライマリ側に保持しておくWALファイルの最小サイズを指定するパラメータだよね。例えば`wal_keep_size = 5GB`と設定すれば、少なくとも5GB分のWALが常に保持される。
これでも一時的なネットワーク瞬断とか、ちょっとしたスタンバイの遅延には対応できるかもしれない。でも、もしスタンバイが数時間、あるいは数日止まってしまったらどうなる?
- 問題点1: 足りない WAL
プライマリの負荷が高くてWALの生成量が爆発的に増えたら、5GBなんてあっという間に消費されて、スタンバイが欲しがるWALが消えちゃう可能性がある。
- 問題点2: 多すぎる WAL
逆に、プライマリのWAL生成量が少なかったとしても、スタンバイが完全に停止してしまったら、5GBで指定したWALはいつか足りなくなる。そして、「よし、もっと保持量を増やそう!」と思って`wal_keep_size`を10GB、20GB…と増やしていくと、今度はプライマリのディスク容量を圧迫し始めるんだ。
結局、`wal_keep_size`は「どれくらいのWALを保持すればスタンバイが追いつけるか」を予測して設定する必要があるんだけど、これは運用負荷やデータ量、ネットワーク状況によって常に変動するから、適切にチューニングし続けるのは非常に難しいんだ。
この予測が外れてスタンバイが追従できなくなったときに、PostgreSQLのエラーログによく出てくるのが、あの悪名高い`WAL file has been removed`メッセージなんだよ。これを見たら、「あ、やばい、バックアップからやり直しか…」って覚悟する瞬間だよね。
レプリケーションスロットが解決すること
レプリケーションスロットを使えば、これらの問題を根本的に解決できる。
レプリケーションスロットは、特定のスタンバイが最後に受け取ったWALの位置(LSN: Log Sequence Number)をプライマリ側で記憶しておいてくれる。そして、そのLSNよりも古いWALファイルは、たとえプライマリ側の他のWAL保持条件が満たされていても、そのスロットが参照するスタンバイが追いつくまで削除しないようにしてくれるんだ。
これによって、
- スタンバイがどれだけ遅延しても、必要なWALがプライマリ側で確実に保持される。
- `wal_keep_size`のように「なんとなく」の容量設定に悩まされる必要がなくなる。
- スタンバイが再接続したときに、確実に過去の時点からレプリケーションを再開できる。
もちろん、無限にWALが溜まり続けるリスクはあるけど、それはまた後で話すね。まずは、この「必要なWALを確実に保持する」というメリットをしっかり理解しておこう。
—
レプリケーションスロットの使い方(物理レプリケーション編)
じゃあ、実際にどうやって使うのか、具体的な手順を見ていこう。
1. レプリケーションスロットの作成
スロットは、プライマリ側で作成するよ。SQLコマンドで簡単に作れる。
SELECT pg_create_physical_replication_slot(‘my_standby_slot’);
- `’my_standby_slot’`:これはスロットの名前だ。スタンバイごとにユニークな名前を付けてあげよう。分かりやすい名前にするのがおすすめ。「`standby01`」とか、「`dr_site_replica`」とかね。
このコマンドを実行すると、プライマリ側には`pg_replslot`ディレクトリ以下にスロット情報が作成されるよ。
2. レプリケーションスロットの確認
作成したスロットの状態や、現在どのWALまで参照しているか(`restart_lsn`)は、`pg_replication_slots`ビューで確認できる。
SELECT FROM pg_replication_slots;
出力例はこんな感じだ。
slot_name | plugin | slot_type | datoid | database | active | restart_lsn | confirmed_flush_lsn | wal_status | safe_wal_size |
—————+——–+———–+——–+———-+——–+————-+———————+————+—————+
my_standby_slot | | physical | | | t | 0/1A0000A0 | | reserved | |
ここで重要なのは、以下の列だよ。
- `slot_name`: さっき作ったスロットの名前。
- `slot_type`: `physical`(物理)または`logical`(論理)。
- `active`: このスロットが現在アクティブなレプリケーション接続に使われているかどうか。`t` (true) なら使われている、`f` (false) なら使われていない。スタンバイが接続を確立すると`t`になるよ。
- `restart_lsn`: ここが一番重要! このスロットが保持しているWALの最小LSNを示す。つまり、このLSNよりも古いWALは、このスロットが参照している限り削除されない。スタンバイがWALを受け取って処理が進むと、このLSNもどんどん先に進んでいくんだ。
- `wal_status`: WALの保持状態を示す。`reserved`(予約済み)、`unreserved`(未予約)、“(空欄)など。`reserved`はWALを保持している状態。
- `safe_wal_size`: このスロットのために保持されているWALのおおよそのサイズ。これがどんどん増えていくようだと注意が必要だ。
3. スタンバイ側の設定
スロットを作成したら、次はスタンバイ側でこのスロットを使うように設定してあげる必要がある。
`primary_conninfo`に`replication_slot`パラメータを追加するんだ。
`postgresql.conf` (または `recovery.conf` – PostgreSQL 12以降は`postgresql.conf`に統合) の設定例:
primary_conninfo = ‘host=primary_host port=5432 user=replicator password=my_password’
primary_conninfo = ‘host=primary_host port=5432 user=replicator password=my_password application_name=my_standby replication_slot=my_standby_slot’
`replication_slot=my_standby_slot`の部分が重要だね。これにより、スタンバイはこの名前のスロットを使ってプライマリと接続し、WALを受け取るようになる。
スタンバイを起動してレプリケーションが開始されると、プライマリ側の`pg_replication_slots`ビューの`active`が`t`になり、`restart_lsn`がスタンバイの追従に合わせて更新されていくのが確認できるはずだ。
4. レプリケーションスロットの削除
不要になったスロットは、忘れずに削除しよう。
SELECT pg_drop_replication_slot(‘my_standby_slot’);
—
レプリケーションスロット利用時の注意点・落とし穴
さて、ここまで聞くと「なんだ、レプリケーションスロットって超便利じゃん!これ使わない手はないな!」って思うよね。その通り、めちゃくちゃ便利な機能なんだけど、強力なツールには必ずリスクが伴う。
レプリケーションスロットの最大の落とし穴は、WALが溜まり続けるリスクだ。
WALが溜まり続けるリスクとディスク容量の逼迫
スタンバイが何らかの理由で停止したり、ネットワークが切断されたりすると、プライマリは「このスタンバイはまだこのWALを処理してないから消せないな」と判断し、WALファイルをどんどん保持し続ける。
これが数時間、数日、あるいは数週間続くとどうなるか?
そう、プライマリ側の`pg_wal`ディレクトリ(または`pg_xlog`)のディスク容量が、あっという間に逼迫してしまうんだ。最悪の場合、ディスクが満杯になってプライマリのデータベースが書き込み不能になり、サービス停止に陥る。
これ、結構あるあるなインシデントなんだよね。「レプリケーションスロットのおかげでWAL不足は起きない!」と安心しきって、スタンバイの監視を怠った結果、痛い目を見るパターンだ。
監視の重要性
このリスクを避けるために、とにかく監視が命だよ。
最低でも、以下の項目は定期的に監視してアラートを出すようにしておこう。
1. `pg_replication_slots`ビューの`active`列: スロットがアクティブ(`t`)になっているか?スタンバイが停止したり切断されたりすると`f`になるから、これを見ればスタンバイの接続状態がわかる。
2. `pg_replication_slots`ビューの`restart_lsn`列の変動: スタンバイが順調に追従していれば、このLSNは常に新しい値に更新されていくはずだ。もしこのLSNが長時間更新されない場合、スタンバイが遅延しているか停止している可能性が高い。
3. `pg_replication_slots`ビューの`safe_wal_size` (または `pg_wal`ディレクトリのサイズ): このスロットが保持しているWALのサイズが、異常に増えていないか?特定の閾値を超えたらアラートを出すようにしよう。
4. スタンバイ自身の状態: プライマリから見ても、スタンバイが正常に動作しているかは別途監視が必要だ。レプリケーション遅延(`pg_stat_replication`ビューの`replay_lsn`と`flush_lsn`の差分など)も見ておこう。
緊急時の対応:スロットの削除
もし、スタンバイが復旧不能になったり、長期間停止していてディスク容量が逼迫してきたりした場合は、そのスロットを削除するという最終手段も考慮する必要がある。
SELECT pg_drop_replication_slot(‘my_standby_slot’);
スロットを削除すれば、そのスロットが保持していたWALファイルは解放され、プライマリ側で通常のルールに従って削除されるようになる。
ただし、これをやってしまうと、そのスタンバイはもうその時点からレプリケーションを再開することはできない。ベースバックアップから取り直すしかなくなるから、本当に最終手段として認識しておこうね。
—
まとめ:レプリケーションスロットは諸刃の剣、理解と監視が鍵!
どうだったかな?レプリケーションスロットについて、少しは理解が深まったかな?
レプリケーションスロットは、WAL不足によるレプリケーション中断という大きな問題を解決してくれる、非常に強力で便利な機能だ。現代のPostgreSQLレプリケーション運用においては、もはや必須と言ってもいいだろう。
でも、それは「WALを削除しない」という強力な効果を持つがゆえに、スタンバイ側の不調や監視の怠慢が、プライマリ側のディスク逼迫、ひいてはサービス停止に直結するという、諸刃の剣でもあるんだ。
だからこそ、
- レプリケーションスロットの仕組みをしっかり理解する
- スタンバイの状態とスロットの状態を常に監視する
- 異常を検知したら迅速に対応する体制を整える
これらの運用とセットで使うことで、初めてその真価を発揮できるんだ。
PostgreSQLを安定して運用していく上で、避けては通れないテーマだから、今日の話を参考に、ぜひ自分の環境でしっかり実装・監視・運用に取り組んでみてほしい。
何か困ったことがあれば、いつでも相談してくれよな!じゃ、また!
コメント