今日は Coarse-Grained Lock、関連した複数のオブジェクトのロックを取得する際のパターンです。
上の図における顧客 (Customer) と住所 (Address) の関係に代表されるように、互いに関連するオブジェクトを一緒にロックしたいというケースがあります。 それぞれのオブジェクトを馬鹿正直にロックする方針を採ると、デッドロックを生じさせないように「個々のオブジェクト」を「正しい順に」ロックしていかないといけなくなります。これを多数の開発者からなるチームに徹底させるのは大変困難です。また、都度、個々のオブジェクトをロックしていくのでは性能劣化も生じます。
Coarse-Grained Lock は、これらの問題を鑑み、複数の関連するオブジェクトをまとめて 1 回だけロックを取得するパターンです。
最初に、個々のオブジェクトを代表してロックするポイントを作ります。よく XX 排他制御用テーブルとか作ったり、「親テーブル」なるものに VERSION
カラムを作ったりしますが、アレですね。
これに関連する概念として、aggregate、root がありますが、Coarse-Grained Lock では、このうちの root をロックすることになることが多いです。
- aggregate: データ変更の単位となるオブジェクトの集合。さっきの図の例だと、Customer と Address が aggregate に相当します。
- root: aggregate の中のオブジェクトを変更する際に、ロック用のアクセスを必要とする対象
これを実現するための方法として、以下の方法があります。
- aggregate に含まれる個々のオブジェクトに root へ直接的にリンクさせる
- 個々のテーブルに、aggregate への外部キーを張るイメージ
- aggregate に含まれる個々のオブジェクトに root へ間接的にリンクさせる
- 直接の親テーブルへの外部キーを保持し、それを繰り返すことによって root を参照するイメージ
- グラフ構造が大きくなると、root に辿り着くまでの参照で性能劣化が起こりがちなので、