理系学生日記

おまえはいつまで学生気分なのか

PoEAA: Coarse-Grained Lock

今日は Coarse-Grained Lock、関連した複数のオブジェクトのロックを取得する際のパターンです。

上の図における顧客 (Customer) と住所 (Address) の関係に代表されるように、互いに関連するオブジェクトを一緒にロックしたいというケースがあります。 それぞれのオブジェクトを馬鹿正直にロックする方針を採ると、デッドロックを生じさせないように「個々のオブジェクト」を「正しい順に」ロックしていかないといけなくなります。これを多数の開発者からなるチームに徹底させるのは大変困難です。また、都度、個々のオブジェクトをロックしていくのでは性能劣化も生じます。

Coarse-Grained Lock は、これらの問題を鑑み、複数の関連するオブジェクトをまとめて 1 回だけロックを取得するパターンです。 最初に、個々のオブジェクトを代表してロックするポイントを作ります。よく XX 排他制御用テーブルとか作ったり、「親テーブル」なるものに VERSION カラムを作ったりしますが、アレですね。

これに関連する概念として、aggregate、root がありますが、Coarse-Grained Lock では、このうちの root をロックすることになることが多いです。

  • aggregate: データ変更の単位となるオブジェクトの集合。さっきの図の例だと、Customer と Address が aggregate に相当します。
  • root: aggregate の中のオブジェクトを変更する際に、ロック用のアクセスを必要とする対象

これを実現するための方法として、以下の方法があります。

  1. aggregate に含まれる個々のオブジェクトに root へ直接的にリンクさせる
    • 個々のテーブルに、aggregate への外部キーを張るイメージ
  2. aggregate に含まれる個々のオブジェクトに root へ間接的にリンクさせる
    • 直接の親テーブルへの外部キーを保持し、それを繰り返すことによって root を参照するイメージ
    • グラフ構造が大きくなると、root に辿り着くまでの参照で性能劣化が起こりがちなので、