【テクニカル・上級編】 プロセス配列 (ProcArray) – PostgreSQL

なぜ我々は「ProcArray」に畏敬の念を抱くべきなのか

PostgreSQLのソースコードを追いかけていると、どうしても避けて通れない場所があります。それが `ProcArray` です。

PostgreSQLにおけるMVCC(多版同時実行制御)の心臓部といえば、誰もが「スナップショット」と答えるでしょう。しかし、そのスナップショットがどのように生成されるのか、あるいは、どの行が「今、誰から見えているのか」を判定する際、その裏で何が起きているのか。そこに深く関わっているのが、この `ProcArray` という共有メモリ構造です。

今日は、教科書的な定義をなぞるのではなく、現場のエンジニアとして、この「プロセスの名簿」が持つ深淵な役割と、そこから生じるパフォーマンストラブルの種について話をしましょう。

—

ProcArray とは何か:全プロセスの「監視塔」

シンプルに言えば、`ProcArray` は、現在稼働しているすべてのバックエンドプロセスの状態を記録した、共有メモリ上の配列です。

各バックエンドは、トランザクションを開始するたびに自身の `PGPROC` 構造体をこの配列に登録します。これにより、PostgreSQLは「今、誰がどのトランザクションID(XID)で動いているのか」を瞬時に把握できるわけです。

特筆すべきは、その「スナップショット生成時の挙動」です。
クエリが実行されるたび、PostgreSQLは `ProcArray` をスキャンし、以下のような情報を抽出してスナップショットを作成します。

  • xmin: 実行中の最小のトランザクションID(これより古いものは確定済み)
  • xmax: 次に割り当てられるトランザクションID(これより新しいものは未コミット)
  • runningXact: 現在実行中の、まだコミットしていないXIDのリスト

ここがポイントです。「実行中のトランザクションのリスト」を生成するために、排他ロックをガチガチに固めてスキャンするのか? 答えはNOです。それでは高負荷時にデータベースが死んでしまいます。PostgreSQLは `ProcArrayLock` という軽量なロックを巧妙に使い、可能な限り並行性を犠牲にしない設計になっています。

—

現場で遭遇する「ProcArray」起因のボトルネック

しかし、どんなに洗練された設計でも、限界はあります。我々がトラブルシューティングの現場で遭遇する「謎の低速化」の多くは、この `ProcArray` の管理に関連しています。

1. ProcArrayLock の競合

もしあなたが、非常に短いトランザクションを毎秒数万回発行するようなシステムを運用しているなら、`ProcArrayLock` の競合に注意を払うべきです。
新しいトランザクションを開始するたび、あるいは終了するたびに、このロックを(共有モードであれ排他モードであれ)取得する必要があります。接続数が数千規模になると、このロックの獲得待ちがCPUを食いつぶし、急激にスループットが低下します。

  • 教訓: コネクションプーリングは単なる「接続数削減」のためだけではありません。`ProcArray` への過度なアクセスを減らすための、スケーラビリティ対策そのものなのです。

2. 巨大なスナップショットのコスト

`ProcArray` をスキャンするコストは、単純に「実行中のトランザクション数」に比例します。
もし、数秒かかるバッチ処理が「アイドル状態」のまま長時間放置されていたらどうなるでしょうか? `ProcArray` にその古いトランザクションが残り続け、スナップショットを生成するたびにその存在を確認しなければなりません。

これは「トランザクションIDの周回」や「VACUUMの遅延」にも直結しますが、もっと根本的な問題として、スナップショット生成処理そのものが重くなり、システム全体のレスポンスを悪化させる原因になります。

—

エンジニアの視点:アーキテクチャを理解するということ

`ProcArray` を意識したチューニングができるようになると、PostgreSQLの挙動が一段と深く見えるようになります。

例えば、`pg_stat_activity` で「Active」なセッションが異常に多いのを見つけたとき、単に「遅いクエリがある」と考えるのではなく、「これらが `ProcArray` を肥大化させ、他の全クエリの可視性判定コストを押し上げている」という動的な構造までイメージできるようになるはずです。

データベースはブラックボックスではありません。この `ProcArray` のように、メモリ上でプロセス同士が互いの状態を監視し合うという、非常に人間臭い、しかし極めて論理的な連携の上に成り立っています。

もし次に、PostgreSQLのパフォーマンスに悩んだら、`pg_stat_activity` を眺めながらこう問いかけてみてください。
「今、この瞬間の `ProcArray` は、どのくらい混雑しているだろうか?」と。

その問いこそが、熟練したエンジニアへの第一歩です。

コメント

タイトルとURLをコピーしました