LAC WATCH

セキュリティとITの最新情報

RSS

株式会社ラック

メールマガジン

サイバーセキュリティや
ラックに関する情報をお届けします。

ラックピープル | 

部内勉強会(ロック)

今回のテーマは「ロック」。重要な機能なのでしっかり理解していきましょう。

ロック

今回のDB2部内勉強会のテーマはロックです。トランザクションのロックをどうやって捌くかがデータベース・エンジンの肝のひとつではないでしょうか。複雑なシステムほどロックに泣かされている(担当者の)ことを耳にします。さらにロックはデータの整合性を維持するためでもあります。
例えば、ある販売システムであるユーザーが商品をひとつ購入するのと同時に別のユーザーでも同じ商品をひとつ購入する処理を実行したとすると、正しくは2個商品が減らなければならないのですが、ロックがないとそれぞれの処理(とくに後からの処理)が正しい個数を取得できないために間違った情報で更新してしまうことになります。そのようなことを防ぐためにもロックがあります。

ロックの種類は細かく別けると多いのですが、ざっくりと大きく3つに別けられます。参照系、更新意図参照系、更新系の3つです。参照ロックはSharedLockというところから「Sロック」と呼ばれています。一番ゆるいロックです。更新意図参照ロックはUpdateLockというところから「Uロック」と呼ばれています。更新を意図した参照実施するときにデッドロック回避を目的に取得されます。更新ロックは他からのロックを排他制御するのでeXclusiveLockというところから「Xロック」と呼ばれています。

ロックの互換性

それぞれのロック同士なので互換性が異なります。すでに取得されているロックに対して、これから取得しようとするロックの種類によってロックが取れるものと取れない(待たされる)ものがあります。ロックが取れないものは「互換性がない」とされます。

ロック互換のマトリクス

ロック互換のマトリクス

ロック競合時のデータの見せ方

データを参照しようとした際に別の処理で該当レコードが更新中だった場合、未コミット状態のため更新前の最新のレコードを参照させる動きをするようになりました(設定により変更可)。そのため、今までは更新中であれば参照処理も待たされることもありましたが、レコードが最新ではない可能性もあるけど待たされることなくコミット済みであるデータが返ってくる動きになっています。

ロックの対象範囲

ロック対象には表スペース、表、レコードの3種類があり、ロックモードによりそれぞれ取得する範囲が決まっています。照会、更新処理実行時には行または表ロックが取得されます。ロックの範囲が広くなれば並行稼動性が低くなるのでロック待ちが発生しやすくなってしまいます。

ロックの保持期間

ロックの保持期間は、作業単位(UnitOfWork)が完了する(Commit/Rollback)まで保持されます。並行稼動性を低下させないためにも頻繁にCommitを実行するようにすることが重要になってきます。分離レベルによって解放タイミングも異なります、分離レベルCSではカーソルが移動すると解放され、分離レベルRSでは選択行にNSロックが残ります。最も強い分離レベルRRでは走査行にSロックが残ります。ロックを残しておくことで他の処理による更新を阻止しているのです。カーソルをCloseしてもロックは外れないので必ずCommitする必要があります。

ロックタイムアウト

要求したロックに対して互換性のないロックが取得されていた場合、先の互換性のないロックが解放されるまで待たされることをロックウェイトといいます。ロックウェイトしている時間がDB構成パラメータのLOCKTIMEOUTに達するとロックタイムアウトとなり、処理はRollbackされてしまいます。(LOCKTIMEOUTの初期値は-1=無限待機なので必ず設定変更するようにしましょう。そのままではエラーにならずにずっと待ち続けてしまいます。)

デッドロック

複数の処理がお互いのロック解放を待ち合って、互いに動きが取れなくなってしまう状況のことです。自動でどちらかの処理がRollbackさせられますが、自動検出機能はあるがこのデッドロック検出機能をあてにしてアプリケーションを作成するべきではありません。デッドロックは好ましくない状況なのでアプリケーションでデッドロックが発生しないような作りにしておく必要があります。

発生要因としては、ロックエスカレーションの発生、アプリケーション内で表ロックの取得、BIND時の分離レベルが不必要に広い、複数のアプリケーションが同じレコードに異なる順番でロックを取得しようとしている、などが挙げられます。

デッドロック発生を回避する方法としては、頻繁にCommitを実施する、ロック範囲が狭い分離レベルの使用、ロックエスカレーションが発生しないように対応する、などが挙げられます。エラー発生時の処理組み込みをしておくことも対応しておきましょう。

デッドロックイメージ

デッドロックイメージ

ロックエスカレーション

ロックの情報はメモリに格納されます。すべての処理でこのメモリを共有しています。こちらもDB構成パラメータのLOCKLISTで最大量を設定します。これを上回ってロックを取得しようとしたり、1アプリケーション(接続)で使用量が規定量を超えた場合に「ロックエスカレーション」が発生し、いままでレコード単位でロックを取得していたが表単位にロック範囲を拡大してロックをひとつにまとめることでLOCKLISTのメモリ使用量(取得済みロック数)を減らす動きをします。ロック範囲が行から表に変わったことで並行稼動性が落ちてしまうので好ましくない動きです。LOCKLISTもMAXLOCKSもデフォルトはAutomatic(構成アドバイザーにより変更されている場合もあります)なので自動変更とすることもできます。

発生原因としては1アプリケーションに許されるロック数を超えてロック保持するアプリケーションがある場合と、ロックに使用しているメモリ量がLOCKLISTを超えた場合があります。

回避方法については、ロック範囲がより狭い分離レベルを使用する、同一表に大量に更新処理がある場合は、あらかじめ表ロックを取得し、処理後に速やかにCommit(ロック解除)を実行する、あるいは頻繁にCommit実施する、などがあります。

ロックエスカレーションイメージ

ロックエスカレーションイメージ

分離レベル

分離レベルとは、トランザクションの中でどの程度厳密にデータの一貫性を保つかを決定するレベルにことです。分離レベルは4つあり、DB2では強い順に、RR → RS → CS → UR となります。RR(RepeatableRead:反復可能読み取り)は走査した行に対してSロックを取得し、索引キーの次のHighキーを持つ行にもSロックを取得します。RS(ReadStability:読取り固定)は結果行に対してNSロックを取得します。CS(CursorStability:カーソル固定)は例外はありますが行へのロックは取得しません(互換性がないロックは待たされます)。もっとも弱いUR(UncommittedRead:未コミット読み取り)は行へのロックは取得しません。

また、これらの分離レベルにおいてそれぞれ発生する事象が変わります。RRでは発生事象はなく同一処理内において、もう一度読み直したときに結果レコードが減ることも増えることも許容しません。RSでは幻像読み取りが発生します。同一処理内において、1回目の参照時の結果レコードが2回目の参照時も結果レコードとして返ってくるレコードが増えることがあります。CSはRSの事象に加え、反復不可能読み取りが発生します。同一処理内において1回目の参照時と2回目の参照時に結果レコードが同じではなく、結果レコードが減ることがあります。URはCSの事象に加え、未コミットデータ読み取りが発生します。
コミットされていないレコードが読み取れることがあるので2回目の参照時にロールバックされて結果レコードから外れてしまう可能性があり、同じ結果が返ってくる保証はありません。

参考資料:
DB2 V9.7 デザインガイド:ロック -基礎編-

この記事は役に立ちましたか?

はい いいえ