Contenu connexe Similaire à トランザクションをSerializableにする4つの方法 (15) Plus de Kumazaki Hiroki (7) トランザクションをSerializableにする4つの方法7. データベース授業あるある
____
/ \ / \ キリッ
. / (ー) (ー)\
/ ⌒(__人__)⌒ \
| |r┬-| |
\ `ー'´ /
ノ \
/´ ヽ
| l \
ヽ -一''''''"~~``'ー--、 -一'''''''ー-、.
ヽ ____(⌒)(⌒)⌒) ) (⌒_(⌒)⌒)⌒))
トランザクションはACIDを守ります。
AはAtomicity
CはConsistency
IはIsolation
DはDurability
を意味します。
8. データベース授業あるある
____
/_ノ ヽ、_\
ミ ミ ミ o゚((●)) ((●))゚o ミ ミ ミ
/⌒)⌒)⌒. ::::::⌒(__人__)⌒:::\ /⌒)⌒)⌒)
| / / / |r┬-| | (⌒)/ / / //
| :::::::::::(⌒) | | | / ゝ:::::::::::/
| ノ | | | \ / ) /
ヽ / `ー'´ ヽ / /
| | l||l 从人 l||l l||l 从人 l||l バンバン
ヽ -一''''''"~~``'ー--、 -一'''''''ー-、
ヽ ____(⌒)(⌒)⌒) ) (⌒_(⌒)⌒)⌒))
だっておwwwwwwww
守ってないおwwww
遅くてやってられないおwwww
11. ロジック例
SET @avail SELECT COUNT(*) FROM doctors WHERE state == “診察可能”;
IF @avail <= 1 BEGIN -- 医師が一人以下なら
RAISEERROR(“診察可能な医師が居なくなります”);
ELSE -- 医師が二人以上いるなら
UPDATE doctors SET state == “予約済み”
WHERE state ==“診察可能”AND name == “田中医者丸”;
COMMIT;
END
• 以下のロジックで良さそうに見える
– なお発表者はストアドプロシージャの文法に詳しくないので以下は
フィーリングでお読みください
13. Write Skew
• 実際にはうまく行かない
– 一覧の取得は命じたが書き換えを禁じてないからcommitがそのまま通る
時間
User2
User1
医師何人?
医師何人?
上記トランザクション群の結果として、診察可能な医師が0人にな
る。これはUser1とUser2のどちらが先に実行した事にもできない。
良さそうなロジックなのにバグってる有名な一例。
2人居るで 2人居るで
じゃあ佐藤さんヨロ
じゃあ田中さんヨロ
ええで ええで
コミット頼む
コミット頼む
OK OK
14. Read Only
• 詳細はA Read-Only Transaction Anomaly Under Snapshot
Isolation(Alanら2004)を参照
• 以下の実行はSerializeできない
時間
Y
X
口座Aを確認
Z
口座Bを確認
口座Aに20万預ける
口座Bから10万引き出す(A+Bが負になるので金利込の11万を減らす)口座Aを確認
コミット
X→Yと仮定すると、最終状態が{A:20, B:-10}にならないとおかしい
つまりYは必ずXの前に来ないとダメ
Y→X→Zと仮定すると、Zは{A: 20, B: -11} を読まないとおかしい
つまりZはYより前でXより後じゃないとダメ
Y→Xの順序と、X→Z→Yの順序は同時に実現できない
15. さあどうする?
• 診察可能医師をSELECTする際にSELECT FOR UPDATEを
利用する(アプリロジックへの侵入)
• “急患待ち”という新たな状態を定義して医師を先にそこ
に割り当ててしまう(業務ロジックへの侵入)
• “急患待ち”の医師が4人以上になるシステムにしておけ
ばWrite Skewが3回起きる可能性はかなり低いでしょ(運
用でカバーする例)
• “急患待ち”状態の医師なんて別に要らんかったんや。
緊急なら診察中の他の医師が何とかするでしょ(解決を
諦める例)
• 分離レベルにSERIALIZABLEを指定 DBの問題は
DBで解決
16. 解決策
• 2 Phase Lockを行う
• Read-Trackingを行う(SSI)
• Read-Validationを行う(SILOその他)
• SQLのレイヤで先にSerializableにしてしまう
17. 解決策
• 2 Phase Lockを行う
• Read-Trackingを行う(SSI)
• Read-Validationを行う(SILOその他)
• SQLのレイヤで先にSerializableにしてしまう
18. 2 Phase Lock
• 手続き全体が成長相と減退相の1つずつから
なるべし
1 2
獲得しているロックの数
時間
成長相 減退相
20. Strict 2 Phase Lock(S2PL)
• 2 Phase Lockに加えて「コミットが済むまで一切ロック解放するべからず」
という条件を加えた物
– カスケードロールバックを回避できるので実用上2PLと言ったらこれの事を指
す事が多い[要出典]
1 2
獲得しているロックの数
時間
成長相 減退相
コミットのタイミングはこれより右に
行ってはいけない
21. 2 Phase Lock
• なんでこの方法ならSerializableになるのかは
Philip A. Bernstein, Vassos Hadzilacos, Nathan
Goodman (1987): Concurrency Control and
Recovery in Database Systems を参照
22. 解決策
• 2 Phase Lockを行う
• Read-Trackingを行う(SSI)
• Read-Validationを行う(SILOその他)
• SQLのレイヤで先にSerializableにしてしまう
23. Read Uncommited
Read Commited
Repeatable Read
Snapshot Isolation
トランザクション分離レベル
• Serializableという安全地帯から出ると様々な
魔物(Anomaly)が襲い掛かってくる
Serializalbe
Write Skew Anomaly
Phantom Read Anomaly
Read Only Anomaly
Non-Repeatable Read Anomaly
Dirty Read Anomaly
24. Snapshot Isolation
• Write Skew AnomalyとRead Only Anomaly以外の
Anomalyが起きないとされているトランザクション分離
レベル
• 全てのトランザクションは、トランザクション開始時の
データベースのスナップショットのみを見ながら走る、
という分離レベル
– Read Repeatableと違ってファントムリード等も起きない
– 物理的に全体のスナップショットを作ったりはしない
• 実装上はMVCC(Multi-Version Concurrency Control)が
用いられる事が多いが、厳密にはそれだけではSIにで
きない
– 理由を説明するにはこの余白は狭すぎる
25. 基本アイデア
• Snapshot Isolationで問題になるのはWrite Skew
AnomalyとRead Only Anomaly[AlanらSIGMOD04]だから、それ
らが起きなくなる仕組みを用意すればSerializableと呼ん
で良いんじゃね?
– 1999年ごろからそのアイデアはあった
– ユーザのSQL文を検査してAnomalyが起きそうかどうか静的チェックする
方法なども検討された
• その結果、TPC-Cの実行はSnapshot IsolationでもAnomalyが起きないパターンである事
が証明されたりなどした
• Snapshot Isolationで発生するAnomalyを検出する方法
考えました!Dependency Cyclic Graph(DSG)を書けばい
けます!
– paper: Making Snapshot Isolation Serializable [Alanら2005]
27. Dependency Serialization Graph
• ついでにRead Only Anomalyも対処できる
時間
B
A
口座Aを確認
A A B A B
Bが読んだ値にAが書き込むので
Anti-Dependency(問題ない)
Aがコミットした値をCが
読むのでDependency
C
口座Bを確認
口座Aに20万預ける
口座Bから10万引き出す(A+Bが負になるので金利込の11万を減らす口座Aを確認
コミット
あかんで
A B
C
Cが読んだ値に
Bが書き込んだので
Anti-Dependency→円環できた
A B
C
30. 解決策
• 2 Phase Lockを行う
• Read-Trackingを行う(SSI)
• Read-Validationを行う(SILOその他)
• SQLのレイヤで先にSerializableにしてしまう
43. 解決策
• 2 Phase Lockを行う
• Read-Trackingを行う(SSI)
• Read-Validationを行う(SILOその他)
• 先にSerializableにしてしまう