[pgsql-jp: 35296] Re: pgpoolのreplication_stop_on_mismatch について

Tatsuo Ishii t-ishii @ sra.co.jp
2005年 4月 20日 (水) 10:30:29 JST


石井です.

> 昨日上記のようにご報告したのですが、その後さらにしつこくテストをしていた
> ところ、master 側と secondary 側のロック順序が入れ替ってしまって pgpool
> が deadlock する、という現象が起こりました。

あらま.

> バックエンドに直接接続して pg_locks を確認してみると (最初 pgpool 経由で
> pg_locks を確認したところ一撃で縮退してしまって驚きました・笑。考えてみ
> れば当たり前)、

うーん,これは考えていなかったですね.なんかうまい対策はないかな...

> master 側では ACCESS EXCLUSIVE ロックにより ACCESS SHARE
> ロック作成をブロックされているトランザクションが、なぜか secondary 側で
> は先に ACCESS SHARE ロックを取得できてしまっていて、そのため master で
> ACCESS EXCLUSIVE ロック確保しているトランザクションが secondary 側での
> ACCESS EXCLUSIVE ロック取得をブロックされてしまって deadlock してしまっ
> た、ということのようでした。
> 
> // ちなみに pgpool レベルで deadlock してしまうと
> // PostgreSQL から見ると単なるアプリケーションレベル
> // のロック待ちのようにしかみえないため、外部から強制
> // 的にコネクションを切断するなりしてあげないとずっと
> // アプリケーションがロックアップ状態になってしまいま
> // す。
> 
> どうしてそのような状況が起こるのか、pgpool-2.5.2 のソースを確認してみた
> ところ、pool_process_query.c の 2227 行目付近で、strict モードの場合でも
				  ~~~~562行目辺りですかね
> SQL が「SELECT」(大文字、小文字問わず) から始まっている場合は master 側
> コネクションからの返事を待たず、secondary 側へ write しているらしいこと
> が分かり (2.5.2 で修正された箇所でしょうか)、そうすると master 側が
> ACCESS EXCLUSIVE ロックによりブロックされている場合でも secondary 側へ
> SELECT が投げられ、ACCESS SHARE ロックを先に確保してしまう場合があるので
> はないかと考えました。

おお,なるほど.たしかに2.5.2でこういう修正を入れました.

> もしその認識が正しいとすると、解決方法としては、
> 
> ・SELECT にも頭に /*STRICT*/ を付ける (本当は /*STRICT*/ でなくても何で
> も良い)。
> ・SELECT の前に明示的に LOCK TABLE 〜 IN ACCESS SHARE MODE する。
> 
> といったことが考えられます。
> 
> 前者の場合、SELECT もシーケンシャルに処理されるようになってしまうため、
> 特に count(*) 系や ORDER BY などを用いたいわゆる「重い」query 時の性能劣
> 化が心配です。そこで、今回は後者で対応してみることにしました。こちらなら
> ば SELECT 自体はパラレルに動作出来ます。

一瞬2.5.2の修正をバックアウトする必要があると思ったのですが,「SELECT 
もシーケンシャルに処理されるようになってしまうため、特に count(*) 系
や ORDER BY などを用いたいわゆる「重い」query 時の性能劣化が心配です」
ということで,それはNGなのですね.

ところで「SELECT の前に明示的に LOCK TABLE 〜 IN ACCESS SHARE MODE す
る」ということは,もはやreplication_strict = trueを指定する必要がない
ような気がするのですが,今はどのようにされていますか?

> これは余談ですが、SELECT で始まる場合は無条件に master/secondary 双方同
> 時に write してしまう今のコードですと、ACCESS EXCLUSIVE ロックを使わない
> 場合でも、例えば SELECT FOR UPDATE などのコードで deadlock してしまう可
> 能性がありそうに思います。deadlock する可能性のある SQL では、たとえ
> replication_strict = true で運用することが決まっているのだとしても、
> /*STRICT*/ 指示子を付けておいた方が安全、ということかもしれません。

おっしゃる通りです.READMEに書いておくべきでした.以下のように修正して
みました.

(旧)
-----------------------------------------------------------------------
   なお,更新を伴う関数を呼び出すような副作用のあるSELECT文を使用して
   いる場合は問題が起きます.このような場合はload_balance_mode"をfalse
   にするか,SELECT文の行頭にスペースや/*NO LOAD BALANCE*/のようなコメ
   ントを挿入して負荷分散されないようにしてください.
-----------------------------------------------------------------------

(新)
-----------------------------------------------------------------------
   なお,当然のことながらSELECT FOR UPDATEや,更新を伴う関数を呼び出す
   ような副作用のあるSELECT文を使用している場合は問題が起きます.この
   ような場合はload_balance_mode"をfalseにするか,SELECT文の行頭にスペー
   スや/*NO LOAD BALANCE*/のようなコメントを挿入して負荷分散されないよ
   うにしてください.
-----------------------------------------------------------------------

> 以上、ご報告でした。それではまた。

ありがとうございました.
--
Tatsuo Ishii



pgsql-jp メーリングリストの案内