4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

OptimisticOfflineLock vs PessimisticOfflineLock

Last updated at Posted at 2022-12-20

20.OptimisticOfflineLock vs PessimisticOfflineLock.png

オフラインシステムと異なり、Web に集約されたシステムは、非同期的に起きる複数の人の操作をリアルタイムに反映しなければならないため、同一データの書き換えの排他制御が重要になってきます。

データベーストランザクションには ACID (Atomicity / Consistency / Isolation / Durability) の特性があります。Isolation (独立性) は、各トランザクションが、途中で他のトランザクションによるデータ操作の影響を受けておかしくならないことを保証する特性です。この特性のおかげで、トランザクション内でのロジックが自己矛盾するような事態は避けられますが、システム全体として見ると不十分です。トランザクションにデッドロックが起きなくても、データに意図しない上書きが置きることはあります。

Optimistic Offline Lock (楽観的ロック) は、同時期に行われた複数のユーザー操作が同じレコード書き換えを起こす問題に対する、現実的な解決策です。

A さんと B さんが同時に、同じデータを編集するための Web フォームにアクセスしました。A さんの方が先に編集結果を送信しました。このあと少し遅れて B さんの編集結果を受け付けます。すると、A さんの操作が失われてしまいます。両者がそれぞれ「在庫 1 つ増えた」を行ったとき、正しい結果は +2 ですが、排他制御がなければ +1 になってしまうわけです。

「少しでも早く編集を開始した方が、他人の編集を禁止できる」という戦略を取ると、複数の人が同時にシステムを使えるメリットが減ってしまいます。操作を開始した人が長期間ロックを握りっぱなしになるおそれもあります。編集しようと思ったけど最終的にやっぱり元通りでいい、なんて場合もよくあります。

楽観的ロックは、この事前のロックを行いません。実際に書き込みが起きるまでは、誰でも何も考えず好きなときに操作を開始できるようにしておきます。代わりに、操作対象のデータにはバージョン番号かハッシュ値のようなものを持たせ、それを「前提とした直前状態」とします。後で書き込もうとした操作が、直前バージョンだと思っていたものと、実際の現在バージョンとに食い違いを見つけると、意図しない上書きとみなして処理を中断させます。これは Git のブランチマージがコンフリクトを起こしたのと同じです。あとになった人には、新しい前提でやり直し (rebase) をしてもらうのが適当です。

Pessimistic Offline Lock (悲観的ロック) は、それでも起きるレベルの同時更新に対する現実解です。まったく同時に押された送信ボタンのうち、たまたま先に操作を開始したプロセスが、他のプロセスを完全にブロックします。そうしなければ、反復可能読み取り排他レベル (Repeatable Read) のトランザクションであっても、それぞれが正しい前提として直前バージョンを読み取り、パラレルワールドを作ってしまうからです。同時に開始されたトランザクションは、他にトランザクションはない、自分は正しいと思い込んで処理を進めてしまい、コミットに行き着いてしまいます。

パフォーマンスよりも絶対的なロックが重要なときは、トランザクションの排他レベルを直列化 (Serializable) することも選択肢のひとつです。が、全体をロックするよりも、テーブルだけ、行だけをロック単位にできるならその方が、他の無関係なプロセスのレスポンスが良くなります。SELECT FOR UPDATE という特殊な SQL で、行をロックキーにできるデータベースが多くあります。

とはいえもちろん、もっと時間のかかる人の操作で、特定のデータを特権ユーザー以外読み取り専用にする、というのも、仕組みとしては悲観的ロックのひとつです。楽観的か悲観的かは、現実的な応用方法よりも、どちらかといえばメカニズムの違いを意味するための語彙です。

インターネットに公開されたシステムでは、排他的な処理が追いつかないほど書き込み操作が多い場合も増えてきました。タイムラグなしの即時反映が求められない場合は、全ての更新処理をやりきってしまわず、CQRS のコマンドとして積んでおき、イベントソーシングで処理する考え方もあります。PoEAA 執筆当時は言われていませんでしたが、イベントソーシングは悲観的ロックの代わりに検討する価値のあるパターンです。

追記:複数の人が同時に更新するようなデータをあまり持たず、データを各持ち主ユーザーに分散させたり、操作権限を明確にしたり、あるいは追記のみのデータベースに記録を付けるなどして、アプリケーション設計でコンフリクトを起こしにくくしたり、被害をおさえるように考えてあることは、そもそも論ですがすごく大事です。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?