萌えハッカーニュースリーダー

2025/07/15 04:43 When Sigterm Does Nothing: A Postgres Mystery

出典: https://clickhouse.com/blog/sigterm-postgres-mystery
hakase
博士

ロボ子、大変なのじゃ!ClickPipesのチームがPostgresのリードレプリカで論理レプリケーションスロットを作ろうとしたら、バグに遭遇したらしいぞ!

roboko
ロボ子

それは大変ですね、博士。具体的にはどのような問題が発生したのでしょうか?

hakase
博士

普通は数秒で終わるクエリが数時間も終わらなくて、Postgresの通常の方法じゃ止められなかったらしいのじゃ。顧客も困るし、本番データベースも危なくなるから大問題だぞ!

roboko
ロボ子

なるほど…。記事によると、ClickPipesはPostgres CDC(Change Data Capture)を大規模に扱っていたPeerDBというスタートアップだったそうですね。CDCはデータベースの変更を継続的に追跡するプロセスとのことですが、Postgresでは主に論理レプリケーションスロットを通じて実行されるのですね。

hakase
博士

そうそう!論理レプリケーションスロットは、WAL(Write-Ahead Log)から変更をデコードして、コンシューマーにストリームして再生するのじゃ。ClickPipesは論理レプリケーションを中心に構築されてるから、スロットの作成は超重要なのじゃ。

roboko
ロボ子

今回の問題は、新しいPostgresリードレプリカからのデータ複製パイプが「スタック」していたとのことですが、`pg_create_logical_replication_slot`クエリが長時間実行されていたことが原因だったのですね。

hakase
博士

`wait_event`が関連付けられていないから、ユーザーはスロット作成がスタックしてることに気づきにくいのがミソじゃな。しかも、ClickPipeを切断してもクエリが止まらないし、`SIGINT`や`SIGTERM`シグナルも効かないってんだから、お手上げなのじゃ。

roboko
ロボ子

レプリケーションスロットが「アクティブ」とマークされてドロップできない状態になり、WALを保持し続けてストレージを圧迫する危険性もあったのですね。顧客はマネージドPostgresサービスを使用していたため、Postgresインスタンスを再起動するしか解決策がなかった、と。

hakase
博士

以前にも同じような問題があって、`hot_standby_feedback`をオンにすると解決したように見えたけど、根本的な解決には至ってなかったのじゃ。今回は、Postgresプロバイダーのサポートから`strace`出力で`nanosleep`のみが繰り返されていることが判明したらしいぞ。

roboko
ロボ子

`nanosleep`ですか。それは、バックエンドが1ms間隔で`sleep()`を繰り返していることを示唆しているのですね。記事によると、再現手順は以下の通りです。 1. プライマリインスタンスとリードレプリカを持つPostgresクラスタ(v16以降)をセットアップ。 2. プライマリでトランザクションを開始し、DML操作を実行(ただし、コミットまたはロールバックはしない)。 3. リードレプリカで`pg_create_logical_replication_slot`を使用して論理レプリケーションスロットを作成。 4. トランザクションをコミットまたはロールバックすると、スロットの作成が完了。

hakase
博士

内部的には、レプリケーションスロットの作成は、スロット作成クエリが発行される前に、トランザクションがコミット/ロールバックされるのを待つ必要があるのじゃ。リードレプリカでは、Postgresインスタンスは「ホットスタンバイ」として機能して、プライマリからのWALレコードを受信してデータのコピーを維持するのじゃ。

roboko
ロボ子

ホットスタンバイは、WALレコードから`KnownAssignedXids`と呼ばれるプライマリで実行されているトランザクションのリストを維持するのですね。トランザクションの完了を待つ関数`XactLockTableWait`は、ロックを取得してトランザクションが進行中かどうかを確認するループを使用しますが、ホットスタンバイの場合、`LockAcquire`がすぐに戻り、`TransactionIdIsInProgress`が`KnownAssignedXids`を考慮してトランザクションが実行中かどうかを判断するため、1msのスリープループに陥ってしまう、と。

hakase
博士

そう!ホットスタンバイでは1msのスリープループに陥り、割り込み処理がないから、プロセスが停止できなくなるのじゃ!しかも、`wait_event`が報告されないから、ユーザーはログを見るまでスロット作成がスタックしていることに気づかないという二重苦なのじゃ!

roboko
ロボ子

ClickPipesチームは、この問題に対処するため、スリープ前に割り込みチェックを追加するパッチをPostgresメーリングリストに提出したのですね。このパッチはすぐに承認され、サポートされているすべてのPostgresの主要バージョンにバックポートされたとのことです。

hakase
博士

別のコミュニティメンバーが`wait_event`の欠如と非効率なループの問題に対処するパッチを提出して、現在議論中らしいぞ。ClickPipesチームは、この問題が単発ではないことを理解して、RCAを特定してパッチを開発したのが素晴らしいのじゃ!

roboko
ロボ子

PostgreSQLからClickHouseへのデータ複製は、カラムナストレージのパフォーマンス、並列クエリ実行、高度な時系列分析を可能にするのですね。ClickHouse CloudユーザーにはClickPipes for Postgresを、セルフホストClickHouseユーザーにはPeerDBを推奨しているとのことです。

hakase
博士

どちらのソリューションもPostgresリードレプリカとシームレスに連携して、プライマリデータベースからのレプリケーションの負荷を軽減するから、安心して使えるのじゃ!

roboko
ロボ子

今回の件で、ClickPipesチームのPostgresへの深い知識と、コミュニティへの貢献がよくわかりましたね。

hakase
博士

ほんとじゃな!しかし、このバグ、まるで私が徹夜でデバッグしてる時の顔みたいじゃ!永遠に終わらないスリープループ…って、ロボ子、笑いすぎ!

⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。

Search