#デッドロック事象
ここ数年聞かなかったけれど、身近なところで、立て続けにデッドロックが発生。事象は次のように簡略化して書くと、本当によくある典型的な事象。
トランザクションA | トランザクションB |
---|---|
Key=1をUPDATE。 | |
Key=2をUPDATE。 | |
Key=2をUPDATE ==>トランザクションB待ち |
|
Key=1をUPDATE ==>デッドロック‼! |
しかし、何でだろう?と思い、もう少し聞いてみたら、そうだねぇと思うところもあったので、注意喚起を込めて書いています。
#デッドロック具体的例
これまでは、jsp+servletでしたが、最近、リッチクライアント化したアプリ。クライアント側のグリッド上で自由にソートしてデータを並べかえられるようになりました。その結果、
1):トランザクションAは、グリッドを昇順ソートした後で更新。
2):トランザクションBは、グリッドを降順ソートした後で更新。
のために、ロックがたすき掛けになって、デッドロックとなりました。
解ってしまえば、そりゃそうだよねだし、何で気がつかなかった、気づいてあげられなかったんだろうと。
ということで、教訓。
#教訓
グリッドで自由にソートできるとするなら、更新順番には気を付けろ!
です。
#最後に、私の場合のデッドロック対策。
設計に入る前のプロジェクトキックオフで、この手のよくある不具合(nullの扱いとか)について、
こんな事例があってとか、このプロジェクトではどうするとかを話します。
いつも同じメンバならよいのですが、そうじゃないときもあるので。
これでメンバの心のどこかに引っ掛かりができると思っています(思いたい)。
あとは、設計時、実装時の「レビュー」による、回避策です。
Aさん、Bさんと複数の人が、その画面からの更新が並列して行えるとして、
その画面から一回の指示で複数レコードを更新するとしたら、その順序は?
その画面から一回の指示で複数テーブルを更新するとしたら、その順序は?
オンライン処理とバッチ処理が並列して行えるとして、
オンライン処理とバッチ処理で複数レコードを更新するとしたら、その順序は?
オンライン処理とバッチ処理で複数テーブルを更新するとしたら、その順序は?
##デッドロック回避策の定義:
回避:複数のトランザクションで、同じ資源のロックが必要なら、同じ順序でロックを取得する。
この順序は、人力に委ねられているため、設計時のミス、実装時のミスをしたら、デッドロックしてしまう。
受容:タイムアウトを指定。デッドロックが検知され、負けた方が、ABEND、もしくはもう一度トランザクションをやり直す。==>トランザクションのやり直しができるということは、そこでデッドロックが起きるとわかっているので、回避に向けた実装ができる。ABENDは、運用保守チームからすると、Noooo、受け入れたくないです。
軽減:トランザクション内の処理時間を短くすることで、デッドロックを起きにくくする。==>どんだけ早くするば?!
転嫁:思い付かない。あるのかな?
#参考:mysqlでデドロックを試す
トランザクションAが倉庫ID=1の商品ID=1234567-01、商品ID=1234567-02の順でロックを取得し、トランザクションBが倉庫ID=1の商品ID=1234567-02、商品ID=1234567-01の順でロックを取得するようなたすき掛けで、デッドロックが発生する様子を見る。
##テーブルの初期状態
mysql> SELECT
-> *
-> FROM
-> T_STOCK
-> WHERE
-> STOCKHOUSE_ID='1'
-> ;
+---------------+------------+--------+--------+---------------------+
| STOCKHOUSE_ID | ITEM_ID | AMOUNT | VER_ID | UPD_DTTM |
+---------------+------------+--------+--------+---------------------+
| 1 | 1234567-01 | 123 | 1 | 2015-09-23 16:33:52 |
| 1 | 1234567-02 | 600 | 1 | 2015-09-23 16:33:52 |
| 1 | 1234567-03 | 702 | 1 | 2015-09-23 16:33:52 |
| 1 | 1234567-04 | 395 | 1 | 2015-09-23 16:33:52 |
| 1 | 1234567-05 | 903 | 1 | 2015-09-23 16:33:52 |
| 1 | 1234567-06 | 679 | 1 | 2015-09-23 16:33:52 |
| 1 | 1234567-07 | 2 | 1 | 2015-09-23 16:33:52 |
| 1 | 1234567-08 | 158 | 1 | 2015-09-23 16:33:52 |
| 1 | 1234567-09 | 518 | 1 | 2015-09-23 16:33:52 |
| 1 | 1234567-10 | 456 | 1 | 2015-09-23 16:33:52 |
+---------------+------------+--------+--------+---------------------+
10 rows in set (0.00 sec)