変更要約: 初版(主題G4・G4.1〜G4.3)
4.1起こりうる障害のパターン
障害トリアージの基本を学びます。エラーメッセージからの障害特定、サーバ停止・データ消失・OSリソース枯渇・プロセス状態分析、タイムアウト系パラメータのstatement_timeout・lock_timeout・idle_in_transaction_session_timeout、クラッシュ後の整合性を左右するsynchronous_commit・restart_after_crash、サーバ制御のpg_ctl、ロック管理の上限max_locks_per_transactionを押さえます。
本番データベースの障害対応は、まず何が起きたかを正確に切り分けるところから始まります。「サーバに接続できない」という一つの症状も、原因はプロセスのクラッシュ、OSのリソース枯渇(ディスク満杯・メモリ不足)、ネットワーク断、あるいは単なる過負荷による接続上限到達など様々です。Gold試験では、エラーメッセージ・プロセス状態・設定パラメータの3方向から障害の性質を特定し、適切な一次対応を選ぶ判断力が問われます。
4.1.1障害の特定:エラーメッセージ・プロセス・リソース
- エラーメッセージからの障害特定=PostgreSQLのログ(
log_destinationで設定した出力先)にはFATAL・PANIC・ERRORなど重大度が付く。PANICはサーバプロセス全体をクラッシュさせ自動再起動を引き起こす最重度で、could not write to file(ディスク書き込み失敗)やout of memory(メモリ枯渇)はOSリソース枯渇の典型的な兆候。 - サーバ停止・データ消失・OSリソース枯渇・プロセス状態分析=
psでPostgreSQLのpostmasterとバックエンドプロセスの生死を確認、df/duでディスク使用量、freeでメモリを確認するのが一次切り分けの定石。ディスクフルは特にWALの書き込み不能に直結し、最悪クラッシュに至るため最優先で除去すべき原因。
4.1.2タイムアウト系パラメータとクラッシュ後の挙動
- statement_timeout=1つのSQL文の実行時間の上限(ミリ秒)。超過すると自動的にキャンセルされる。長時間クエリの暴走を防ぐ代表的な安全弁。
- lock_timeout=ロック取得待ちの上限時間。ロック待ちがこれを超えるとエラーで中断(statement_timeoutより先に効くことが多い)。idle_in_transaction_session_timeout=トランザクションを開始したままアイドル状態が続くセッションを自動的に切断するタイムアウト(長時間ロック保持による他セッションのブロックを防ぐ)。
- synchronous_commit=コミット確定を待つ強度を制御するパラメータ(on/off等)。offにするとコミット応答は速いが、クラッシュ時に直近のコミット済みトランザクションが失われうる(同期レプリケーションの確実性にも関わる)。restart_after_crash=バックエンドプロセスが異常終了(クラッシュ)した際にサーバ全体を自動的に再起動するかどうかを制御するパラメータ(既定on)。
- pg_ctl=サーバプロセスを制御する標準コマンド(
start/stop/restart/reload/status)。異常終了からの復旧ではpg_ctl startで再起動を試み、クラッシュリカバリ(WALの再生)が自動的に走ることを理解しておく。max_locks_per_transaction=サーバ全体のロックテーブルのサイズを決める係数(トランザクション数×この値が目安上限)で、超過するとout of shared memoryエラーとなり大量のロックを要する操作(多数テーブルの一括操作等)が失敗しうる。
「PANICは全体クラッシュ+自動再起動を招く最重度」「statement_timeout=文単位・lock_timeout=ロック待ち単位・idle_in_transaction_session_timeout=アイドルトランザクション切断」「synchronous_commit=offはコミットが速いがクラッシュ時に直近分を失いうる」「restart_after_crash=バックエンドクラッシュ時の自動再起動制御」「max_locks_per_transaction超過はout of shared memory」が最頻出です。3つのタイムアウトパラメータの対象範囲の違いを正確に区別できるかが得点の鍵です。
実際のインシデント対応は「症状の観測→原因の仮説→一次対応→恒久対策」という流れで進めるのが定石です。例えば「アプリケーションから突然接続エラーが多発し、サーバログにPANIC: could not write to file "pg_wal/..."が出ている」という状況を考えます。まず症状の観測としてpg_ctl statusでプロセスの生死、df -hでディスク使用率を確認します。ディスクフルが原因であれば、これがまさにWALの書き込み不能によるPANICという仮説が裏付けられます。一次対応は不要なファイル(古いログ・一時ファイル)を削除して空き容量を確保し、pg_ctl startでサーバを起動し直すことです。このときrestart_after_crashがonであれば自動的にクラッシュリカバリ(WAL再生)が走り、最後のチェックポイント以降のトランザクションをWALから再現して整合性のある状態に戻ります。恒久対策としては、ディスク使用率の監視アラート追加や、WALアーカイブ先の容量確保、あるいは長時間アイドルのまま接続を保持するアプリケーションのバグをidle_in_transaction_session_timeoutで緩和する、といった再発防止策を講じます。もう一つの典型例は「特定のバッチ処理だけがERROR: out of shared memoryで失敗する」ケースです。これは大量のテーブル・パーティションに同時にロックを取得する処理がmax_locks_per_transaction×(想定接続数)の上限を超えたことが原因である可能性が高く、バッチを分割するか、当該パラメータの見直し(再起動を要する設定変更)を検討します。このように、エラーメッセージの文言そのものが原因パラメータへの最短の手がかりになる点を意識すると、初見の障害でも切り分けが速くなります。
| パラメータ | 対象範囲 | 超過/該当時の挙動 |
|---|---|---|
| statement_timeout | 1つのSQL文の実行時間 | 該当文が自動キャンセル |
| lock_timeout | ロック取得の待ち時間 | エラーで待機中断 |
| idle_in_transaction_session_timeout | トランザクション中のアイドル時間 | セッションを自動切断 |
ひっかけ: 「statement_timeoutはロック取得待ちにも適用される」は誤りです。ロック待ち固有の上限はlock_timeoutで別パラメータです。また「synchronous_commit=offにすればデータが失われることは一切ない」も誤り=offはコミット応答の高速化とのトレードオフで、クラッシュ直後の未フラッシュなトランザクションが失われうるリスクを許容する設定です。「restart_after_crashをoffにすればクラッシュ自体が起きなくなる」も誤り=これはクラッシュ後に自動再起動するかどうかの制御にすぎず、クラッシュの発生自体を防ぐものではありません。
4.1.3この節のまとめ
- エラーメッセージ(PANIC/FATAL/ERROR)とプロセス/リソース状態(ps・df・free)から障害を切り分ける。PANICは全体クラッシュ+自動再起動を招く最重度
- statement_timeout(文単位)/lock_timeout(ロック待ち)/idle_in_transaction_session_timeout(アイドルトランザクション)を区別。synchronous_commit/restart_after_crashでクラッシュ耐性を制御・pg_ctlで起動制御・max_locks_per_transaction超過はout of shared memory
進捗の記録にはログインが必要です。
理解度チェック
(軽い確認用)Q1. 本番サーバのログに "PANIC: could not write to file \"pg_wal/...\"" が出力され、直後にサーバプロセス全体が停止・再起動した。この状況について正しい説明は?
Q2. あるバッチジョブだけがロック待ちの段階で長時間止まってしまい、他のトランザクションをブロックし続けている。ロック取得待ちの上限時間を設定してこの種の長時間ブロックを打ち切りたい場合に使うパラメータは?
Q3. コミット応答のレイテンシを下げるため synchronous_commit を off に変更することを検討している。この変更が伴うリスクとして正しい説明は?

