Software Transactional Memo

STM関係のことをメモっていこうと思います。

分散ロックという名の過ち

f:id:kumagi:20180326043110j:plain

TL;DR;
「分散ロック」が分散システムの設計図に登場した時
だいたいその設計は間違っていて本当に必要なものはトランザクション

 

並行システムを実装する際にロックを用いるのはとても自然なことだ。

僕も普段はロックフリー系のアルゴリズムに詳しいと言われがちだが知識量でいったら実はロック系の方が多く蓄えているかも知れない。
分散システムは並行システムであることが多いので、その中にロックが登場するのはとても自然な発想である。
よく「分散」「並行」「並列」の言葉の定義がごっちゃになっているケースがあり、この記事の主題にしたいわけではないので深くは言及しないが、分散システムは環境などの要因で突如として参加者が音信不通になったり復活したりする点で並行システムと大きく異なる。

並行システムと同じノリで分散システムを設計しようとした際に陥る頻出の過ちが「分散ロック」である。そのアイデアはとても簡単で「多重化して信頼できるシステムの上に、データや処理のアクセス権限の管理を集約する」というものである。そんなものが必要なケース、結構あるのだ。googleのシステムアーキテクチャの話の中にChubbyがロックマネージャの名を冠して出てくるのは自然である。

例えばクラウド上でVMを立てるよう依頼された時、VMをただ立てるだけなら適当な物理マシンの中だけで完結するのだが、立てたVMが外と通信できるようにするためにはネットワーク周りで複数の箇所に一度に更新が必要である。それはちゃんと作ると「ネットワーク機器のコンフィグを流しこめばすぐ」なんて日本語で書くほどに簡単な作業では完結しない。まず適切に排他しなくてはならないし、ロックを使えば問題が完結するだろう、と考えてしまうのがダメというのが本稿の主題である。

分散システムでは参加者は突然いなくなることが普通なので、ロックを獲得したままクライアントがシステムから離脱してしまうことを前提として設計しなくてはならない。ロックサービスを提供する側のサーバがどれだけ完璧なアルゴリズムとマシンで頑健にできていようと、サービスを享受する側のクライアントが離脱するのは分散システムである以上避けられないのだ。

ロックを獲得した参加者が離脱すると獲得されたロックは永久に解放されなくなってしまう。それを避ける為に「ロックを握ってる奴が応答を返さなくなったらロックを無理やり開放する」というのもやりがちな対策だが、それをやると更に問題が2つに増える。

・応答を返せなかったのではなく、たまたま忙しくて応答が遅れただけでは?
・無理やりロックを解放したとして、作業をどこまで進めたかわからないと切り戻しも引き継ぎもできないのでは?

前者は追いかける程にSplit-Brainの様相を呈してくる。後者はつまるところ分散システム頻出の話題となる。これらを個別に対策して…と繰り返す事もできるが複雑度が増すばかりで完全な解決に至るのは果てしない道のりである。

2つの問題を一気に解決するなら「ロックを握ってる奴の生死に関わらず、任意のタイミングでロックは開放してもいいし、やりかけの作業はいつでも全部ロールバックorロールフォワードができる仕組みにする」という形に落としこむしかない。それは最終的にトランザクションのようなatomicityを分散システムの上に作りこむことになる。分散ロックは実はリーダー選出以外の何物でもなくてリーダー引き継ぎや状態の復旧の仕組みまでちゃんと作ると結局トランザクションの再発明に至りがちなのである。

だから、分散システムの設計を議論する際に「分散ロック」という言葉が出てきたら、その言葉を発した人はおそらくそれがゆくゆくはトランザクションに至る長い道のりであることに無自覚であることが経験上多い。自分でも「これがただのマルチスレッドプログラムだったらロックで書いてるな」と思ってしまった時はこのパターンに陥っている。

経験の深い分散システムアーキテクトは専門家への説明に「分散ロック」という言葉を使う事はまずない。おそらく似たような目的のために「リーダー選出」という言葉を使うだろう。更にリーダーを選出するだけでは問題は解決しないので、その後のシステムをトランザクションのように注意深く設計していく。

 

画像はFlickrのCC BY-SA 2.0ライセンスの物を借りました。 Love Locks | Dubrovnik, Croatia | Flickr

追記:

絶対にトランザクションを実装しないといけないのか?というのも実は割と難しい問題で、冪等リトライのパターンに落としこんでしまうのが一番合理的で単純なのでその方向に知恵を絞って上手く行くことが多い。