web-dev-qa-db-ja.com

楽観的ロックと悲観的ロック

マルチユーザーデータベースデスクトップアプリケーションのコンテキストでは、同時実行性の問題を考慮する必要があります。
多くの記事は、楽観的ロックと悲観的ロックの2つのモデルに焦点を当てています。
悲観的ロックでは、レコードへの同時アクセスが予想されるため、リソースがロックされているため、更新中に他のユーザーがアクセスできないようにします。

楽観的ロックでは、同時更新の可能性をあり得ないイベントと見なし、リソースをロックしないようにアプリケーションを設計します。これにより、管理されていないアクセスからデータが失われる可能性があるため、競合を検出し、発生した場合にエラーを発生させるために、トークンフィールド、タイムスタンプ、リビジョン番号などに基づくメカニズムを実装します。

並行性の競合を系統的に(つまり、データベースのほとんどまたはすべてのテーブルで)検出するシステムを設計することは、難しい作業ではないかもしれませんが、些細なことでもありません。通常、ORMによって実行されます。

しかし、これは話の半分にすぎません。競合が検出されたときに解決策があるはずだからです。
多くの記事では、「それがリモートであるため」という考えが浮上しているようですが、この解決策は何とか簡略化できます。たとえば、競合が発生し、データをリロードする必要があるというメッセージをユーザーに表示するとします。しかし、「別のユーザーがデータを変更したので、それらを上書きしますか、それとも再ロードしますか?」のようなメッセージはどうですか?どのデータが変更されたかについての情報を提供しなければ、それは少し馬鹿げたことになります。
本格的な実装では、違いを強調する必要があります。 GUIは、一種のオンザフライ比較をホストする必要があります。これまでのところ、これらの実装の多くを見たことがありません。テストの必要性は言うまでもなく、実装としては非常に困難なようです。また、最も意味のあるフィールドのみを考慮したこの比較の簡略化バージョンを実装することは簡単な作業ではなく、最も基本的なケースでのみ簡単になる場合があります。しかし、この点についての楽観的ロックグロスに関する記事のほとんどは。

質問

楽観的ロックの側面には、2つの等しく不満のあるオプションから選択することを強制する「戦略」があります。 1つは、「より高いコストでの正確さ」です。これは、イベントの可能性に比例しないコストです。もう1つのオプションは、単純化された実装よりも「部分的」です。

しかし、その後、イベントが本当にそれほど遠くにある場合、悲観的ロックを使用することはmoreに意味がありませんか?少なくともデスクトップアプリケーションでは?最も基本的な形式では、非常に単純な実装です。実装に関するコストは、イベントの可能性に比例して返されます。非効率性の観点からのコスト(ロックがない方が常にロックよりも速い)は、イベントの速度が遅いため、同じです。

最近のすべての慣行に反するように思われるため、私がこの推論を続けることは非常に困難です。 Entity FrameworkとEntity Framework Corecoreは、すぐに使える楽観的ロックをサポートしていますが、悲観的ロックはネイティブでサポートされておらず、データベース固有のSQLが必要です。楽観的ロックは、全面的に地位を獲得しています。私が考慮していない重要なことはありますか?
ロックシステムの設計について、orm-optimisticロッキングまたはdb-pessimisticロッキングがどのように機能するかだけでなく、良い記事はありますか?

3
AgostinoX

衝突が非常にまれで、オプティミスティックロックが深刻なオプションである場合、たとえ衝突の解決が少し不格好であっても、それが1年に1回以下の頻度で発生する場合、それはどのような役割を果たすでしょうか?ただし、これが1日に30回発生することを恐れている場合、楽観的ロックはおそらくユースケースのオプションではありません。非常にシンプルで非常に効果的な競合解決を提供できるとしても、その解決にも時間がかかり、その間にデータが他のユーザーによって再度変更される可能性があるため、中間から解決せずに1つの解決から次の解決に実行する可能性がありますデータベースにヒットする状態。

オプティミスティックロックは、最初からすべての種類のデータに適しているわけではありません。主な利点は並列化です。 1人のユーザーが常にフィールドA、B、およびCに触れ、別のユーザーが常にC、D、Eに触れるが、フィールドCはほとんど触れられない場合、悲観的ロックは、ユーザー2がフィールドを編集するためのロックを保持している間、ユーザー1がフィールドAを編集できないことを意味します。 D.しかし、なぜですか。彼らは同時に両方のフィールドを編集できますが、これは競合しません。したがって、ユーザー2は理由もなくユーザー1の作業を遅くします。ただし、常に一緒に処理する必要があるデータフィールドが1つだけまたはフィールドのセットがある場合は、並列化はできません。

バージョン管理システムについて考えてみてください。開発者が異なるファイルまたは同じファイルの異なる部分を編集する限り、すべてが大丈夫です。それらが同じファイルの同じ部分に触れる場合のみ、競合が発生し、この競合を解決する必要があります(変更を選択するか、他の変更を選択するか、両方の変更を手動でマージします)。バージョン管理システムの場合、ペシミスティックロックは、一度に1人の開発者だけがプロジェクトで作業できるか、1人の開発者だけが特定のファイルに一度に触れることができるため、パフォーマンスが低下します。

悲観的ロックによる並列化は、データをチャンクに分割でき、チャンクを個別にロックでき、ユーザーが同時に同じチャンクに触れたい場合にのみ有効です。しかし、大量のデータ損失チャンクを必要とする楽観的ロックは巨大であり、意味のあるマージが不可能であることもオプションではありません。

2
Mecki

どちらのロック戦略にもコストがあります。

機能的要件(無限ループの危険、データ履歴の表示、統合ロジック)を考慮すると、楽観的ロックはより高価になります。

悲観的ロックは、技術的な観点からより高価です(タイムアウト、ネストされたロック、分散ロック、ロックの粒度)

問題が発生したいずれのオプションも、ユーザーと開発者にとって苦痛です。

機能フローとリスク(確率*影響)を注意深く評価すると、特定の問題に最も適したロック戦略が何かについてのガイダンスが得られます。

1
Erno

データを入力する際のロックの実際の解決策は、単にロックの必要性を設計することです。

たとえば、Employeeテーブルにパスワードハッシュ、住所の詳細、現在の給与のフィールドがある場合、これらの詳細を更新するための3つの独立した画面が必要です。各画面は、制御するフィールドのサブセットのみを更新するデータベースと通信する必要があります。ORMがこれをサポートしていない場合は、より適切なORMを使用してください。

したがって、2人のユーザーが同じ住所の詳細を更新しようとしている場合、問題はビジネスレベルにあります。通常、単純な「最終更新の勝利」戦略で十分です。

楽観的または悲観的ロックが必要になる状況は常にありますが、これらはまれです。

1
kiwiron