レプリカの命綱!WALレプリケーションスロットを使いこなして、データ消失の危機からシステムを守ろう
おいっす!データベースの運用、お疲れ様!
今日は、PostgreSQLのレプリケーションでめちゃくちゃ重要なんだけど、意外と「なんとなく」で使ってたり、あるいは「よくわかんないから触らないでおこう…」って避けてる人もいるかもしれない、WALレプリケーションスロットについて、俺の経験も交えながら、ガッツリ解説していこうと思う。
レプリケーションって、冗長化や読み取り負荷分散のために欠かせない技術だけど、その心臓部とも言えるのがWAL(Write-Ahead Log)だ。プライマリで書き込まれたデータ変更は、まずWALに記録されて、それがレプリカに転送されて適用される。
でもさ、ここで一つ問題が出てくるんだ。「レプリカが追いつけなくなったら、プライマリ側のWALファイルってどうなるの?」って。もしレプリカが遅れてる状態で、プライマリが古いWALファイルをどんどん削除していったら…? そう、レプリカが復旧できなくなってしまうんだ!最悪の場合、データ消失につながりかねない、まさに悪夢だ。
それを防いでくれるのが、今回紹介する「WALレプリケーションスロット」なんだ。これ、マジで「レプリカの命綱」って言っても過言じゃない。
WALレプリケーションスロットって、一体全体どういう仕組みなの?
簡単に言うと、WALレプリケーションスロットは、「プライマリ側で、レプリカが必要としているWALファイルを削除しないように、お守りしてくれる仕組み」なんだ。
レプリカがプライマリに接続する際、このレプリケーションスロットを「予約」する。すると、プライマリは、そのスロットが管理しているWALファイル(まだレプリカに送れていない、あるいはレプリカがまだ適用していないWALファイル)を、レプリカがちゃんと受け取って処理するまで、絶対に削除しないようになるんだ。
これは、プライマリ側の`pg_wal`ディレクトリ(PostgreSQLのバージョンによっては`pg_xlog`)をクリーンに保とうとする自動削除の仕組みとは独立して動作する。つまり、「レプリカが追いつくまで、強制的にWALファイルを残しておけ!」っていう、強力な命令なんだね。
具体的な動作イメージ
1. スロットの作成: まず、プライマリ側でレプリカのためにレプリケーションスロットを作成する。
2. レプリカの接続: レプリカは、このスロットを指定してプライマリに接続し、WALストリーミングを開始する。
3. WALの送信: プライマリは、レプリカにWALファイルをストリーミングで送信する。
4. 進捗の記録: レプリカは、受信したWALファイル(または、その中の特定のLSN: Log Sequence Number)をプライマリに通知する。
5. スロットによる保持: プライマリは、レプリカからの通知(WAL受信位置)を受け取るたびに、レプリケーションスロットの「確認済みWAL位置」を更新する。そして、「確認済みWAL位置」よりも古いWALファイルは、レプリカが追いついていなくても削除されないようにする。
6. WALの削除: レプリカが正常にWALを適用し、その進捗がスロットの「確認済みWAL位置」を追い越した時点で、初めて古いWALファイルは安全に削除される。
この仕組みのおかげで、レプリカが一時的にダウンしたり、ネットワークの調子が悪くてWALの受信が遅れたりしても、プライマリ側のWALが勝手に削除されて、レプリカが同期できなくなる、なんて事態を防げるんだ。
どんな時に使うの? 実践的なユースケース
「へぇ、便利そうだけど、具体的にどんな時に使うの?」って思うよね。いくつか、俺が実際に遭遇した、あるいは「これ使っとけ!」って思うシーンを挙げてみよう。
- ホットスタンバイ構成の安定化:
これが一番の王道。レプリカをホットスタンバイとして動かしている場合、レプリカがプライマリと同期できなくなるのは致命的。レプリケーションスロットを使えば、レプリカが多少遅れても、WALが消えてしまう心配がなくなる。
- 一時的なレプリカの停止・再起動:
レプリカサーバーのメンテナンスや、OSのアップデートなどで一時的にレプリカを停止する必要がある時。スロットがあれば、停止中にプライマリのWALが勝手に消えて、再起動後に同期に失敗する、なんてことを防げる。
- 論理レプリケーション(`pglogical`や`decoder plugin`):
論理レプリケーションでは、WALの特定の変更を抽出してレプリカに送る。この場合も、抽出・転送のプロセスが遅れると、WALが削除されてしまうリスクがある。レプリケーションスロットは、このリスクを回避するために必須と言える。
- ストリーミングレプリケーションの初期同期:
新しいレプリカを構築する際、プライマリからWALをストリーミングで受信する。この初期同期の最中にWALが消えてしまうと、同期が中断してしまう。スロットを用意しておけば、安心して初期同期を進められる。
- `pg_basebackup`との併用:
`pg_basebackup`でフルバックアップを取得する際も、バックアップ中のWALを確実に取得するために、レプリケーションスロットと連携させることが推奨されている。
実際に使ってみよう! クリエイト&チェック
じゃあ、実際にどうやって使うのか、コマンドを見ていこう。
1. レプリケーションスロットの作成
プライマリサーバーで、以下のSQLを実行する。
— スロットを作成するコマンド
— slot_name: スロットの名前 (任意)
— TYPE: ‘physical’ または ‘logical’
— METHOD: 論理レプリケーションの場合、使用するデコーダープラグイン (例: ‘pgoutput’)
— 例1: 物理レプリケーション用スロットの作成
CREATE_REPLICATION_SLOT my_physical_slot LOGICAL DEPRECATED; — 物理レプリケーションではLOGICALは非推奨なので、実際はTYPEを指定しないか、PostgreSQL10以降ならTYPE=physicalを指定
— PostgreSQL 10以降の場合、物理レプリケーションスロットは TYPE を指定しないのが一般的
CREATE_REPLICATION_SLOT my_physical_slot;
— 例2: 論理レプリケーション用スロットの作成 (publication ‘my_publication’ に紐づける場合)
— PostgreSQL 10以降で pgoutput デコーダーを使う場合
CREATE_REPLICATION_SLOT my_logical_slot LOGICAL OUTPUT PLUGIN (name = pgoutput);
— PostgreSQL 9.4 以降で pglogical デコーダーを使う場合 (pglogical拡張が必要)
— CREATE_REPLICATION_SLOT my_logical_slot LOGICAL OUTPUT PLUGIN (name = pglogical);
ポイント:
- `CREATE_REPLICATION_SLOT` は、スーパーユーザー権限が必要だよ。
- `slot_name` は、後でレプリカ側から指定するので、分かりやすい名前にしておこう。
- `TYPE` は、物理レプリケーションなら指定しないか、`physical` を指定(PostgreSQL 10以降)。論理レプリケーションなら `logical` を指定し、さらに `OUTPUT PLUGIN` で使用するデコーダープラグインを指定する。
- 注意: `LOGICAL DEPRECATED` は古い書き方で、物理レプリケーションでは非推奨になっている。PostgreSQL 10以降では、`CREATE_REPLICATION_SLOT slot_name;` で物理スロットが作成される。
2. レプリカ側の設定
レプリカ(スタンバイ)サーバーの `postgresql.conf` や `recovery.conf` (PostgreSQL 9.x) または `postgresql.conf` の `primary_slot_name` パラメータで、作成したスロット名を指定する。
`postgresql.conf` (PostgreSQL 10以降) の場合:
プライマリサーバーの接続情報
primary_conninfo = ‘host=your_primary_host port=5432 user=repluser password=…’
使用するレプリケーションスロット名
primary_slot_name = ‘my_physical_slot’ # 作成したスロット名に合わせる
`recovery.conf` (PostgreSQL 9.x) の場合:
プライマリサーバーの接続情報
standby_mode = ‘on’
primary_conninfo = ‘host=your_primary_host port=5432 user=repluser password=…’
使用するレプリケーションスロット名
primary_slot_name = ‘my_physical_slot’ # 作成したスロット名に合わせる
レプリカを再起動すれば、指定したスロットを使ってプライマリに接続し、WALストリーミングが開始される。
3. スロットの状態を確認する
プライマリサーバーで、以下のビューをクエリすると、スロットの状態を確認できる。
— レプリケーションスロットの一覧と状態を確認
SELECT FROM pg_replication_slots;
出力例:
slot_name | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | wal_status | safe_wal_size | oid
————–+——–+———–+——–+———-+——–+————+——+————–+————-+————+—————+—–
my_physical_slot | | physical | | | t | 12345 | | | 0/167A0A0 | extended | 16777216 | 16384
my_logical_slot | pgoutput | logical | 16384 | my_db | t | 54321 | | | 0/167A0E8 | extended | 16777216 | 16385
重要なのは以下のカラム:
- `slot_name`: スロットの名前
- `active`: `t` ならレプリカが接続中。`f` なら切断されている。
- `active_pid`: 接続中のレプリカのプロセスID (PostgreSQL 10以降)
- `restart_lsn`: このスロットが保持しているWALのLSN。これより古いWALは削除されない。
- `wal_status`: `extended` ならWALが保持されている状態。`lost` になると、WALが失われたことを意味する(これはまずい!)。
- `safe_wal_size`: このスロットが保持しているWALの合計サイズ。
4. レプリカが切断された場合
レプリカが長期間切断されたり、スロットの設定を間違えたりすると、`active` が `f` になり、`restart_lsn` がどんどん進まなくなる。その間、プライマリ側ではWALファイルが溜まり続けることになる。
もし、レプリカが復旧しないまま、プライマリのディスク容量が圧迫されてしまうと、システム全体が停止するという、最悪の事態になりかねない!
5. スロットの削除
レプリケーションを完全に停止したり、スロットが不要になったりした場合は、必ず削除しよう。削除しないと、WALファイルが永遠に残り続けて、ディスクを圧迫し続けることになる。
— スロットを削除するコマンド
SELECT pg_drop_replication_slot(‘my_physical_slot’);
注意: スロットを削除する前に、本当にそのスロットが不要であることを確認すること!間違って削除して、後からレプリカが同期できなくなると、目も当てられないことになる。
運用上の注意点とトラブルシューティング
レプリケーションスロットは便利だけど、いくつか注意しておきたい点がある。
- ディスク容量の圧迫:
これが一番の落とし穴。レプリカがオフラインだったり、WALの受信が遅延している状態で、スロットを削除せずに放置しておくと、プライマリのディスク容量がみるみるうちに食いつぶされる。
定期的に `pg_replication_slots` をチェックして、`active` が `f` になっているスロットがないか、`restart_lsn` が古すぎるスロットがないかを確認する習慣をつけよう。
- レプリカの同期遅延:
レプリカ側で `primary_slot_name` の設定ミスや、ネットワークの問題でWALを受信できていない場合、スロットはWALを保持し続けるが、レプリカは同期しないまま。
レプリカの同期状態は、`pg_stat_replication` ビューなどで常に監視することが重要。
- スロットの「紛失」:
稀に、何らかの理由でレプリカが WAL を受信したにも関わらず、その情報がプライマリに正しく伝わらず、スロットの `restart_lsn` が更新されないことがある。
この場合、`wal_status` が `lost` になることがある。これは、スロットが保持しているWALが、レプリカが既に受信・適用したWALよりも古い状態になっていることを意味し、非常に危険な状態。
このような状態になったら、スロットを削除し、レプリカを再同期(`pg_basebackup`など)する必要がある。
- 論理レプリケーションのデコーダープラグイン:
論理レプリケーションで `pgoutput` などのデコーダープラグインを使用する場合、そのプラグイン自体の設定や、レプリカ側の `publication` の設定も正しく行われているか確認が必要。
- パフォーマンスへの影響:
WALファイルが溜まりすぎると、プライマリのディスクI/Oに影響を与える可能性がある。特に、頻繁にWALファイルが生成されるような高負荷なシステムでは、スロットの管理を怠らないように注意が必要だ。
まとめ:レプリケーションスロットは、賢く使ってこそ真価を発揮する!
WALレプリケーションスロットは、PostgreSQLのレプリケーションにおいて、レプリカの同期を確実に維持し、データ消失のリスクを回避するための非常に強力な機能だ。
- レプリカを運用するなら、基本的にはレプリケーションスロットを使うことを強く推奨する。
- スロットを作成したら、必ずレプリカ側で `primary_slot_name` を設定するのを忘れないように。
- 定期的にプライマリ側の `pg_replication_slots` をチェックし、不要なスロットや、レプリカがオフラインになっているスロットがないか監視する。
- レプリカが長期間オフラインになった場合は、ディスク容量の圧迫に注意し、必要であればスロットを削除してレプリカを再同期する判断も必要になる。
- スロットを削除する際は、本当に不要か、慎重に確認する。
このスロットをうまく使いこなせれば、レプリケーションの安定性が格段に向上するはずだ。もし今まで「なんとなく」で使っていた人も、この機会に仕組みを理解して、より自信を持って運用できるようになってほしい。
何か質問があれば、いつでも聞いてくれ! 次回は、もっとディープなPostgreSQLの話でもしようかな!
コメント