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

Tsunehisa Kazawa kazawa @ ca2.so-net.ne.jp
2005年 4月 21日 (木) 21:24:04 JST


こんばんは。加澤です。HA チャレンジの続報です。

// いい加減うっとうしいですね。すみません。

とりあえず、
・参照時は明示的に ACCESS SHARE ロックをかける
・更新時も明示的に ACCESS EXCLUSIVE ロックをかける
とすることでうまく動くようになったかに見えたのですが、さらにいろいろテス
トしているうちにまた新たな (というか間抜けな) 問題に当たりました。

ご存じの通り ACCESS EXCLUSIVE ロックは全てのロックと競合するため、このま
まの状態では pg_dump も concorrent vacuum もかけられないことに気が付きま
した(^^;。正確にはどちらも実行可能ですが、実行中トランザクションがロック
してしまいます。これはイタい。

改めて考えてみると、そもそも、どうして ACCESS EXCLUSIVE ロックを使ってい
たのかと言えば、SELECT で暗黙にかけられる ACCESS SHARE ロックと競合させ
たかったがためで、現在のように参照時にも明示的にロックをかけることにした
のであれば、ACCESS SHARE/ACCESS EXCLUSIVE などという一番強力なロックを使
う必要はないのでした。

そこで、利用するロックを ROW SHARE/EXCLUSIVE に切り替えたところ、これま
で通りそれなりにちゃんと動作しつつ、無事 pg_dump や vacuum も平行して動
作させられるようになりました (正確には更新と vacuum は同時に動けません
が、このくらいならば許容範囲です)。

// 同じ話として、OID の生成をシリアライズするために行っている
// pg_database へのロックも、ACCESS EXCLUSIVE のままではちと
// 強力すぎたため EXCLUSIVE へ変更しました。

***

上のような対策を行って、アプリケーションコード上のロック順も常に厳密に一
致するようにして、さあこれで完璧、と思っていたのですが、さらにしつこくテ
ストしていると、また deadlock が発生してしまいました。ただ今度は pgpool
レベルではなく、PostgreSQL backend がハンドルできるタイプの deadlock です。

さすがに今度はコードをいくら見直しても原因が分からず、ちょっと途方に暮れ
ていたのですが、そうこうするうちに、はっ!とあることに思い当たりました。

今回のアプリケーションでは、テーブル設計時にかなりきちんと外部キーなどの
定義を行ってみていました。中には ON DELETE CASCADE や ON DELETE SET NULL
などをセットしたものもありました。つまりそれらの制約により、暗黙に対象
テーブル以外のテーブルが操作され、その際に異なる順序でロックが確保される
ことがあったのです。

具体的には、参照元のテーブルを更新する際には、参照元に ROW EXCLUSIVE
ロックがかかった後に参照先のテーブルに ROW SHARE ロックがかかります。
ON DELETE SET NULL などがセットされている参照先のテーブルを DELETE した
場合には、参照元のテーブルに ROW EXCLUSIVE ロックがかかってから、参照先
のテーブルに ROW EXCLUSIVE ロックがかかることが分かりました。

これら暗黙の更新に伴うロック順を確認して、順序が違うものはあらかじめ正し
い順序で明示的にロックを行うようにしたところ、とりあえず deadlock は起こ
らなくなりました。

// 「TRIGGER や REFERENCES はトラブルの元」という話はよく
// 聞いてはいましたが、これほど実感したのは初めてかも(^^;。

以上です。それではまた。

-- 
  ◇   加澤恒央 Tsunehisa KAZAWA
◇  ◇ mailto:kazawa @ ca2.so-net.ne.jphttp://www.digitune.org/



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