クイック解決策
現在使用中のスロットを削除するには、それを開いているバックエンドプロセス(PID)を終了させる必要があります。ターミナルまたは SQL コンソールで以下の3つのコマンドを実行してください。
-- 1. スロットを使用している PID を特定する
SELECT active_pid
FROM pg_replication_slots
WHERE slot_name = 'my_subscription_slot';
-- 2. そのプロセスを終了させる
-- 1234 をステップ 1 で取得した PID に置き換えてください
SELECT pg_terminate_backend(1234);
-- 3. 直ちにスロットを削除する
SELECT pg_drop_replication_slot('my_subscription_slot');
根本原因
PostgreSQL は、ワーカープロセス(Walsender)がデータをアクティブにストリーミングしている間、レプリケーションスロットをロックします。このロックは予期せぬデータ損失を防ぐためのものです。サブスクライバーが接続されている状態でスロットを削除しようとすると、PostgreSQL はストリームを保護するためにエラーをスローします。
通常、以下のようなシナリオでこのエラーが発生します:
- サブスクライバーのインスタンスがまだ稼働しており、データをプルしようとしている。
- Debezium や Airbyte などの CDC ツールがアクティブな接続を保持している。
- ネットワークの不具合により、タイムアウトしていない「ゴースト」プロセスがサーバー上に残っている。
- Kubernetes ポッドがクラッシュループに陥り、500ミリ秒ごとに再接続を繰り返している。
解決手順
1. アクティブなプロセスの特定
どのプロセスがスロットを保持しているかを確認します。pg_replication_slots ビューの active_pid 列を確認してください。この列に数値が入っている場合、そのスロットはロックされています。
SELECT slot_name, active, active_pid
FROM pg_replication_slots
WHERE slot_name = 'my_subscription_slot';
2. クライアントの特定
やみくもに実行せず、何を終了させようとしているのかを把握しましょう。スロットのビューと pg_stat_activity を結合することで、アプリケーション名や IP アドレスを確認できます。
SELECT
s.slot_name,
a.application_name,
a.client_addr,
a.backend_start
FROM pg_replication_slots s
JOIN pg_stat_activity a ON s.active_pid = a.pid
WHERE s.slot_name = 'my_subscription_slot';
3. 終了と削除
Debezium のようなサービスが稼働している場合、PID を終了させた瞬間に再接続される可能性があります。まずコンシューマーアプリケーションを停止してください。アプリを停止できない場合は、終了コマンドと削除コマンドを間髪入れずに実行する必要があります。
-- 接続を終了させる
SELECT pg_terminate_backend(active_pid)
FROM pg_replication_slots
WHERE slot_name = 'my_subscription_slot';
-- 直ちにスロットを削除する
SELECT pg_drop_replication_slot('my_subscription_slot');
再接続競争に勝つ方法
マネージドサービスや Kubernetes ポッドは、数ミリ秒で再接続することがよくあります。次のコマンドを入力する前にスロットが再びアクティブになってしまう場合は、以下の戦略を試してください。
オプション A: サブスクライバーを無効化する(推奨)
**移行先(送信先)**のデータベースでサブスクリプションを停止します。これがスロットを解放する最もクリーンな方法です。
-- サブスクライバー(移行先)データベースで実行してください
ALTER SUBSCRIPTION my_sub DISABLE;
ALTER SUBSCRIPTION my_sub SET (slot_name = NONE);
その後、パブリッシャー側に戻り、干渉を受けることなくスロットを削除します。
オプション B: セミコロンによる一括実行
2つのコマンドを1行で実行します。これにより、クライアントが再接続する隙を最小限に抑えられます。
SELECT pg_terminate_backend(active_pid) FROM pg_replication_slots WHERE slot_name = 'my_subscription_slot'; SELECT pg_drop_replication_slot('my_subscription_slot');
なぜこれがディスク容量にとって重要なのか
アクティブでありながら遅延しているレプリケーションスロットは、ストレージ容量を圧迫する隠れた原因になります。これにより PostgreSQL は WAL ファイルを無期限に保持し続けることを強制されます。放置された1つのスロットが、わずか数時間で 200GB 以上の pg_wal 容量を消費したケースもあります。スロットを削除すれば、次のチェックポイント時に PostgreSQL が自動的にこのスペースを回収します。
よくある落とし穴
- 権限: スロットを管理するには、スーパーユーザー権限または
REPLICATIONロールが必要です。 - クラウドの制限: AWS RDS では
pg_drop_replication_slotは通常通り動作しますが、スロットを自動的に再作成するマネージド AWS DMS タスクを使用していないか確認してください。 - プライマリ vs レプリカ: スロットは、それが作成されたノードでのみ削除できます。リードレプリカで実行するとエラーになるため、必ずプライマリインスタンスで実行してください。

