Hitachi

ノンストップデータベース HiRDB Version 10 UAP開発ガイド


3.4.4 デッドロックと回避策

〈この項の構成〉

(1) デッドロックの発生要因

二つのトランザクションが二つ以上の資源の確保をめぐって互いに相手を待つ状態となり,そこから先へ処理が進まなくなることをデッドロックといいます。

デッドロックは,一般に参照のトランザクションと更新(削除を含む)のトランザクションとの間で多く発生します。したがって,UAPのアクセス順序を変えることで,デッドロックの発生頻度を低減させることができます。

デッドロックの例として,二つのトランザクションが同一キーを持った行に対して同時に実行した場合に排他の掛かる順序とデッドロックの関係を次の図に示します。

図3‒12 デッドロックの例

[図データ]

また,ページ排他の場合には,UAPのアクセス手順を統一しても,デッドロックが回避できないことがあります。

ページ排他でのデッドロックの例を次の図に示します。

図3‒13 ページ排他でのデッドロックの例

[図データ]

図「ページ排他でのデッドロックの例」で示した例の場合,クラスタキーを指定していないと,ページへの行の格納順序を一定にできないため,ページ単位にUAPのアクセス順序を統一できません。このような場合には,ALTER TABLEでページ排他を行排他に変更してデッドロックを回避してください。

(2) サーバ間で発生するデッドロック

デッドロックは,一つのサーバ内で発生する以外にサーバとサーバの間でも発生します。HiRDB/パラレルサーバでは,サーバ間で発生するデッドロックのことをグローバルデッドロックといいます。

グローバルデッドロックは,一般に図「ページ排他でのデッドロックの例」で示したような一つのサーバ内で発生するデッドロックと同様に,参照のトランザクションと更新のトランザクションとの間で発生します。したがって,UAPのアクセス順序を変えることで,デッドロックの発生頻度を低減させることができます。

グローバルデッドロックの例として,二つのトランザクションが別々のサーバに格納された表に対して,検索と更新の順番を逆順で実行した場合に排他の掛かる順序とデッドロックの関係を次の図に示します。

図3‒14 グローバルデッドロックの例

[図データ]

図「グローバルデッドロックの例」で示した例の場合,各バックエンドサーバでは,UAP1とUAP2との間の排他制御になりますが,フロントエンドサーバ側からは,お互いに排他待ちとなっているのでデッドロックになります。

(3) デッドロックの検出

各ユニット内でのデッドロックは,それぞれのユニット内の排他制御機構が検出します。HiRDBでは,各ユニット内で同一サーバが排他したリソースについては,そのサーバ内の複数トランザクション間のデッドロックの検出を行います。しかし,同一ユニット内であっても,別サーバにわたるリソース間でのデッドロックについては,排他制御のタイムアウトによってHiRDBが検出する以外では,検出できません。複数のユニットにわたるリソース間のデッドロックについては,ユニット内の別サーバ間のデッドロックと同じであり,タイムアウトによって検出します。

(a) デッドロックの検出方法とタイミング

排他制御処理を分散させているかどうかによって,デッドロックが発生したときの検出方法とタイミングが異なります。排他制御処理の分散については,マニュアル「HiRDB システム運用ガイド」を参照してください。デッドロックの検出方法とタイミングを次の表に示します。

表3‒22 デッドロックの検出方法とタイミング

pd_lck_deadlock_checkの値

pd_lck_pool_partitionの値

デッドロックの検出方法

デッドロックの検出タイミング

Y

2以上

デッドロック監視プロセスによって,定期的に検出を実行します(インターバル監視方式)。

pd_lck_deadlock_check_intervalオペランドに指定した間隔で検出します。この場合,デッドロック発生から検出までに時間差が発生します。

1

サーバプロセスによって,排他待ちになった時点で自己検出します(即時検知方式)。

デッドロック発生後,即時に検出します。

N

デッドロックを検出しません。この場合,pd_lck_wait_timeoutオペランドに指定した時間が経過するまで排他待ちを行った後,UAPに対して排他タイムアウトとしてエラーを発行します。

(凡例) −:該当しません。

注※

フロントエンドサーバの場合はpd_fes_lck_pool_partitionオペランドの値。

(b) デッドロック検出の無効化

pd_lck_deadlock_checkオペランドにNを指定することで,排他制御でのデッドロック検出を無効にできます。

デッドロックの検出方法がインターバル監視方式の場合は,排他制御用プールパーティション数を増加するとデッドロックの検出タイミングごとに排他制御の性能が劣化するおそれがあります。そのため,デッドロックが発生しない業務システムでは,デッドロック検出をしないことでSQLの実行性能が改善することがあります。この場合は,デッドロックが発生しない業務システムを構築した上で,デッドロックの検出を無効にすることを推奨します。

反対に,デッドロックが発生する業務システムでは,デッドロック検出を無効にしないでください。デッドロック検出を無効にすると,デッドロックが発生したときにpd_lck_wait_timeoutオペランドに指定した時間が経過してタイムアウトするまでSQLがエラー終了しません。また,HiRDBがデッドロック情報を出力しなくなるため,デッドロックが発生した要因が分からなくなるおそれがあります。

(4) デッドロックの対策

デッドロックの発生原因は,大きく分けると次の二つになります。

デッドロックは,次の図で示した以外の種類もあります。

デッドロックの主な種類とその対策を次の表に示します。

表3‒23 デッドロックが発生する処理と対策

デッドロック資源

発生原因

対     策

行と行

UAPのアクセス順序※1

  • UAPのアクセス順序を統一する。

  • LOCK TABLEによって表に排他を掛ける。

  • デッドロック発生後にUAPを再実行する。

行とインデクスキー

検索と更新との間の逆順処理※2

  • 検索行を更新しない。

  • 列を同じ値で更新しない。

  • インデクスの定義を必要最小限にする。

  • LOCK TABLEによって表に排他を掛ける。

  • NOWAIT検索をする。

  • デッドロック発生後にUAPを再実行する。

  • インデクスキー値無排他を適用する。

インデクスキーと

インデクスキー

UAPのアクセス順序

  • UAPのアクセス順序を統一する。

  • インデクスの定義を必要最小限にする。

  • LOCK TABLEによって表に排他を掛ける。

  • NOWAIT検索をする。

  • デッドロック発生後にUAPを再実行する。

  • インデクスキー値無排他を適用する。

ページとページ

ページへの行格納順序の不定※3

  • ALTER TABLEによってページ排他を行排他に変更する。

注※1 図「グローバルデッドロックの例」のような場合

注※2 図「デッドロックの例」のような場合

注※3 図「ページ排他でのデッドロックの例」のような場合

(5) デッドロックプライオリティ値による排他制御

デッドロックが発生した場合,どちらのトランザクションをエラーとするかをデッドロックプライオリティ値で制御できます。この制御は,システム定義のpd_deadlock_priority_useオペランドで,デッドロック優先順位を制御する指定をし,クライアント環境定義のPDDLKPRIOオペランドでデッドロックプライオリティ値を指定した場合に,その指定値によってHiRDBがデッドロック優先順位を決定します。

指定した値が小さい方が処理の優先度が高く,値が大きくなるほどエラーになってロールバックする可能性が高くなります。また,デッドロックプライオリティ値が同じ場合,後発の方がエラーとなってロールバックさせられます。

PDDLKPRIOオペランドの指定を省略した場合,UAP,ユティリティ,及び運用コマンドの種別によって,自動的にHiRDBがデッドロックとなったトランザクションのどれかをエラーにしてロールバックさせます。PDDLKPRIOオペランドの指定値を省略した場合に仮定される値については,「クライアント環境定義の設定内容」を参照してください。

デッドロックによって暗黙的にロールバックされたUAPは,ROLLBACK文,又はDISCONNECT文でトランザクションを終了させないと,SQL文を実行してもエラーになります。また,OLTP環境でX/Openに従ったアプリケーションプログラムをクライアントとした場合に,実行したアプリケーションプログラムがデッドロックになったときもトランザクションの終了が必要です。

なお,デッドロック発生時にデッドロック情報を出力したい場合,システム定義のpd_lck_deadlock_infoオペランドにYを指定する必要があります。pd_lck_deadlock_infoオペランドについては,マニュアル「HiRDB システム定義」を参照してください。

(6) デッドロックの回避策

デッドロックは排他の範囲を広くすることで発生頻度を低減できますが,同時実行性は低下します。したがって,排他の範囲を狭くすると同時実行性は向上しますが,不正参照,及び不正更新を引き起こしたり,デッドロックの発生率が増加します。同時実行性を保ちながら,デッドロックを回避するため,次に示す対策を考慮する必要があります。

以上のように,排他制御の範囲を考慮する以外にデッドロックを回避するためには,SQL文の種類とインデクスの種別による排他制御の順序について考慮する必要があります。詳細については,「SQL文の種類とインデクスの種別による排他制御の順序」を参照してください。

(7) プラグインが使用する論理ファイルのデッドロック回避策

プラグインが論理ファイルを使用する場合,更新操作の場合はEXモード,検索操作の場合はPRモードで,論理ファイル単位に排他を掛けます。

論理ファイルの排他は,データの値に関係なく操作発生を契機に実行されます。したがって,論理ファイルを使用するプラグイン定義のある列をアクセスする場合に,更新トランザクションを実行すると,該当する列を操作するほかのすべてのトランザクションとの間に,論理ファイルの競合が発生します。このため,論理ファイルを使用するプラグイン定義のある列を更新するプログラムは,できるだけ単独で実行するようにしてください。