- PR -

PostgreSQL 8.x 万が一のデッドロック対策

1
投稿者投稿内容
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2006-09-01 16:22
 質問は、

・PostgreSQL でマルチスレッド環境での複数の単純 update ステートメント発行時に、自動的に行レベルの Exclusive モードが掛かるのかどうか(つまり、select for update 呼出しの必要が無くなるのかどうか)

・deadlock_timeout の値を、150000 ぐらいに設定するつもりですが、マルチスレッド環境におけるストアドプロシジャーの update 文実行中に、この値を超えてタイムアウトし、デッドロックを検出したとして、マルチスレッドによる複数トランザクションの内、失敗したトランザクションの「失敗」をどうやってハンドリングするのか(戻り値
のみ?若しくはグローバルエラー変数が存在?)、又どうやって失敗したトランザクションを再実行するのか?

教えて下さい。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2006-09-02 01:50
引用:

コブラさんの書き込み (2006-09-01 16:22) より:
・PostgreSQL でマルチスレッド環境での複数の単純 update ステートメント発行時に、自動的に行レベルの Exclusive モードが掛かるのかどうか(つまり、select for update 呼出しの必要が無くなるのかどうか)



select for updateが必要であるかはマルチスレッドと無関係だと思います。
updateの前にロックを獲得しなければならないのなら必要、という所でしょう。

引用:

・deadlock_timeout の値を、150000 ぐらいに設定するつもりですが、マルチスレッド環境におけるストアドプロシジャーの update 文実行中に、この値を超えてタイムアウトし、デッドロックを検出したとして、マルチスレッドによる複数トランザクションの内、失敗したトランザクションの「失敗」をどうやってハンドリングするのか(戻り値
のみ?若しくはグローバルエラー変数が存在?)、又どうやって失敗したトランザクションを再実行するのか?



デッドロック検出時は制約の違反等と同じようにエラーが返ると思いますよ。
再実行するのであれば、rollbackしてもう一度同じSQLを実行しましょう。

マルチスレッドなのはクライアントですか?サーバーですか?
戻り値やグローバルエラー変数って何のことですか?
libpqですか?jdbcですか?それともサーバー側ですか?
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2006-09-03 00:36
サーバー・クライアントの物理的な分離は無く、同じマシンの同じプログラムで擬似的にサーバーソケット担当、クライアントソケット担当の役割に分かれてます。両方共がマルチスレッドです。

各々のスレッドが同じDBをアクセスしますし、更新もします。絶対にロックは必要やと思います。

>戻り値やグローバルエラー変数って何のことですか?

unix の errno みたいな変数があるのかな、と。

>libpqですか?jdbcですか?
libpq です。

>デッドロック検出時は制約の違反等と同じようにエラーが返ると思いますよ。
>再実行するのであれば、rollbackしてもう一度同じSQLを実行しましょう。

あれですよね、Postgres には deadlock_timeout ってありますね。
これ、タイムアウトした時(デッドロック検出時) ROLLBACK したいんですが、単なるエラーで必ずロールバックでエエんですかね?

デッドロック時の固有エラー番号とか返るんでしょうか?
デッドロック時には現在一回きりのストアドプロシジャー呼出しを、トランザクション正常終了までループ実行するような実装でええんでしょうか?
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2006-09-04 02:56
引用:

コブラさんの書き込み (2006-09-03 00:36) より:
サーバー・クライアントの物理的な分離は無く、同じマシンの同じプログラムで擬似的にサーバーソケット担当、クライアントソケット担当の役割に分かれてます。両方共がマルチスレッドです。



これってサーバーもクライアントも、PostgreSQLから見たらどちらも
PostgreSQLのクライアントであることに変わりないのでは?

複数のクライアントが同時にトランザクションを実行することになるので、
複数リソースを更新するのならばロックの管理(確認?)は必須だと思います。

引用:

あれですよね、Postgres には deadlock_timeout ってありますね。
これ、タイムアウトした時(デッドロック検出時) ROLLBACK したいんですが、単なるエラーで必ずロールバックでエエんですかね?



デッドロックしてるのに、ロールバック以外の何が出来るのでしょう?
検出できた時点でロールバック以外の選択肢はあり得ないと思います。
検出できなければ永遠に固まったままですので。

最低限の対策という意味では回復しているわけです。

引用:

デッドロック時の固有エラー番号とか返るんでしょうか?
デッドロック時には現在一回きりのストアドプロシジャー呼出しを、トランザクション正常終了までループ実行するような実装でええんでしょうか?



実装と要件次第だとは思いますが、諦めるのもありでしょう。
そもそもデッドロックはロックの順序をきっちり規定してあげれば
起こらない現象なので、把握できないほどに複雑な順番でロックする
ような設計ならば、デッドロック以外でも問題出まくりな気がします。
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2006-09-04 08:53
>これってサーバーもクライアントも、PostgreSQLから見たらどちらも
>PostgreSQLのクライアントであることに変わりないのでは?

RDMS から見たら、そういう事になります。どちらもクライアントです。

>複数のクライアントが同時にトランザクションを実行することになるので、
>複数リソースを更新するのならばロックの管理(確認?)は必須だと思います。

やっぱ select for update は要りますね。了解しました。

>デッドロックしてるのに、ロールバック以外の何が出来るのでしょう?
>検出できた時点でロールバック以外の選択肢はあり得ないと思います。
>検出できなければ永遠に固まったままですので。

知りたいのは、9/2 の書込みであしゅ氏は
「デッドロック検出時は制約の違反等と同じようにエラーが返ると思いますよ。」
と言われてますが、これって"エラー"の一括りで全部をデッドロック検出と見なす処理
にしてエエのかどうか、又ROLLBACK後のストアドプロシジャーの呼出しを成功するまで何度も再試行するものなのか、という点です。

ロールバック以外の選択肢は考えてません。

>実装と要件次第だとは思いますが、諦めるのもありでしょう。
>そもそもデッドロックはロックの順序をきっちり規定してあげれば
>起こらない現象なので、把握できないほどに複雑な順番でロックする
>ような設計ならば、デッドロック以外でも問題出まくりな気がします。

自分もそう思います。
が、どのスレッドがどういう順番で実行され、その結果どのDBにアクセスするか、
ちょっとアプリの設計レベルでは把握できんのでは?
との観点から今回の質問が必要になってしまいまして。。。>あしゅ氏
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2006-09-05 02:29
引用:

コブラさんの書き込み (2006-09-04 08:53) より:
と言われてますが、これって"エラー"の一括りで全部をデッドロック検出と見なす処理
にしてエエのかどうか、又ROLLBACK後のストアドプロシジャーの呼出しを成功するまで何度も再試行するものなのか、という点です。



PostgreSQLってエラーコードありましたっけ?
っと思って調べてみたら、8.1から実装されてるんですね。
http://www.postgresql.org/docs/8.1/static/errcodes-appendix.html

引用:

自分もそう思います。
が、どのスレッドがどういう順番で実行され、その結果どのDBにアクセスするか、
ちょっとアプリの設計レベルでは把握できんのでは?
との観点から今回の質問が必要になってしまいまして。。。>あしゅ氏



スレッドの実行順序とロックの順序は関係ないと思いますよ。
各スレッドが一定の基準に従った順序でロックすればいいので。

例えば、在庫管理で、ある拠点の在庫を複数更新する場合は、

1. 在庫の所有者(=拠点)をFOR UPDATEしてから更新する
2. 在庫のキーでソートした順序で更新する

の、どちらか(or 両方)に統一していればいいわけです。
この辺をちゃんと設計している方が希少かもしれませんが。。
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2006-09-05 02:38
逆に考えると、エラーコードが無い場合どうやってロールバックを検知し、
どうやってストアドプロシジャーの再試行やるんでしょうか。。。

しかし、このエラーコード 4000 は使えそうですな。
いや、わざわざ有難うございました。>あしゅ氏

>例えば、在庫管理で、ある拠点の在庫を複数更新する場合は、

>1. 在庫の所有者(=拠点)をFOR UPDATEしてから更新する
>2. 在庫のキーでソートした順序で更新する

>の、どちらか(or 両方)に統一していればいいわけです。

1. の方に統一しようと思います。
かたじけないっす。
1

スキルアップ/キャリアアップ(JOB@IT)