MySQL における楽観的ロック、悲観的ロック、MVCC の包括的な分析

MySQL における楽観的ロック、悲観的ロック、MVCC の包括的な分析

序文

データベースの実際の使用では、データの書き込みや読み取りを同時に行わないことが必要な状況によく遭遇します。たとえば、フラッシュセールのシナリオでは、2 つのリクエストが同時に、システムにまだ在庫が 1 個あることを読み取り、その後、在庫を 0 に更新します。これにより、売れ過ぎの状況が発生し、商品の実際の在庫が記録と一致しなくなります。

リソースの競合によって生じるデータの不整合などの問題を解決するには、データへの正しいアクセスと変更を保証するメカニズムが必要です。データベースでは、このメカニズムがデータベースの同時実行制御です。その中で、楽観的同時実行制御、悲観的同時実行制御、およびマルチバージョン同時実行制御は、データベース同時実行制御に使用される主な技術的手段です。

悲観的同時実行制御

自然

Wikipedia: リレーショナル データベース管理システムでは、悲観的同時実行制御 (「悲観的ロック」とも呼ばれ、略して「PCC」) は同時実行制御の方法です。トランザクションが他のユーザーに影響を与えるような方法でデータを変更することを防ぎます。トランザクションがデータ行を読み取ってロックを適用する操作を実行する場合、そのトランザクションがロックを解除すると、他のトランザクションはロックと競合する操作のみを実行できるようになります。

実は、私たちがよく話題にする悲観的ロックは実際のロックではなく、並行性制御の考え方です。悲観的並行性制御はデータの変更に対して悲観的であり、外部からデータにアクセスすると必然的に競合が発生すると考えています。そのため、データ処理のプロセスではロックを使用して、リソースの排他的使用を確保します。

データベースロックの仕組みは、実際には悲観的同時実行制御の観点から実装されており、実際の使用状況に応じて、データベースロックは多くのカテゴリに分類できます。詳細については、後の記事を参照してください。

実装

データベース悲観的ロックのロック プロセスは次のとおりです。

トランザクションを開始した後、操作の種類に応じてロックが必要なデータに特定の種類のロックを適用します。たとえば、共有行ロックなどです。ロックが成功した場合は、後続の操作を続行します。データが他のロックによってロックされており、今追加するロックと競合する場合、ロックは失敗します (たとえば、排他ロックが追加された場合)。このとき、他のロックが解除されるのを待つ必要があります (デッドロックが発生する可能性があります)
トランザクションが完了したらロックを解除します

長所と短所

アドバンテージ:

悲観的同時実行制御では、「最初にロックを取得し、成功したらデータにアクセスする」という保守的な戦略を採用しています。これにより、データの取得と変更が秩序正しく実行されるため、書き込みが多く読み取りが少ない環境での使用に適しています。もちろん、悲観的ロックを使用すると非常に高いパフォーマンスを維持することはできませんが、楽観的ロックではより良いパフォーマンスが得られないという前提の下では、悲観的ロックはデータのセキュリティを確保できます。

欠点:
ロックが必要であり、ロックの競合やデッドロックが発生する可能性があるため、悲観的同時実行制御ではシステムのオーバーヘッドが増加し、システム効率が低下し、システムの並列性も低下します。

楽観的同時実行制御

自然

Wikipedia: リレーショナル データベース管理システムでは、楽観的同時実行制御 (「楽観的ロック」、楽観的同時実行制御とも呼ばれ、略して「OCC」) は同時実行制御方式です。複数ユーザーの同時トランザクションは処理中に互いに影響を及ぼさず、各トランザクションはロックを生成せずに影響を受けるデータの一部を処理できることを前提としています。
楽観的同時実行制御は、データの変更について楽観的であり、同時実行環境であっても、データに対する外部操作によって通常は競合が発生しないと考えているため、データをロックしません。代わりに、各トランザクションは、データの更新を送信する前に、まず、トランザクションがデータを読み取った後に他のトランザクションがデータを変更したかどうかを確認します。他のトランザクションがトランザクションを更新した場合、競合情報が返され、ユーザーは再試行やロールバックなどの続行方法を決定できます。

楽観的ロックは実際にはロックではなく、同時実行制御を実装するためにロックも使用していないことがわかります。代わりに、他の方法を使用して、データが変更可能かどうかを判断します。楽観的ロックは、通常、ユーザーによって実装されるロック メカニズムです。実際のロックは使用されませんが、ロック効果を生み出すことができます。

実装

CAS (Compare and swap) は、よく知られているロックフリー アルゴリズムです。ロックフリープログラミングとは、ロックを使用せずに複数のスレッド間で変数の同期を実現すること、つまりスレッドがブロックされることなく変数の同期を実現することを意味し、ノンブロッキング同期とも呼ばれます。非ブロッキング同期を実装する方式は、「ロックフリー プログラミング アルゴリズム」と呼ばれます。

楽観的ロックは基本的に CAS (Compare and swap) アルゴリズムに基づいて実装されます。まず、CAS プロセスを見てみましょう。CAS 操作のプロセスは、次の C コードで表すことができます。

int cas(long *addr, long old, long new)
{
 /* アトミックに実行します。 */
 if(*addr != 古い)
  0を返します。
 *addr = 新しい;
 1 を返します。
}

CAS には、メモリ値 V、古い期待値 A、および変更される新しい値 B の 3 つのオペランドがあります。期待値 A とメモリ値 V が同じ場合のみ、メモリ値 V を B に変更し、それ以外の場合は何もしません。 CAS 操作全体はアトミック操作であり、分割できません。

楽観的ロックの実装は、主に次の点で上記のプロセスと似ています。

  • バージョン番号タグ: テーブルに新しいフィールド「version」を追加します。これはバージョン番号を保存するために使用されます。データを取得するときに、同時にバージョン番号を取得し、次のコマンドを使用してデータを更新します: update xxx set version=version+1,… ここで、… version="old version" であり、… です。このとき、返された結果内の影響を受けた行数が 0 であるかどうかを判断して、更新が成功したかどうかを判断します。更新が失敗した場合は、他のリクエストによってすでにデータが更新されていることを意味します。
  • タイムスタンプ: バージョン番号と同じですが、タイムスタンプによって決定されます。一般的に、多くのデータテーブルには更新時刻フィールドがあります。このフィールドを使用して判断することで、新しいフィールドを追加する必要はありません。
  • 更新するフィールド: タイムスタンプ フィールドがなく、新しいフィールドを追加したくない場合は、更新するフィールドを使用して判断することを検討できます。更新されたデータは一般的に変更されるため、更新する前に、更新するフィールドの古い値とデータベースの現在の値を比較できます。変更がない場合は更新します。
  • すべてのフィールド マーク: データ テーブル内のすべてのフィールドが判断に使用されます。これは、いくつかのフィールドだけでなく、データ行全体をロックするのと同じです。この行のデータが変更される限り、更新されません。

長所と短所

アドバンテージ:

楽観的同時実行制御では、実際にはロックが行われないため、追加のオーバーヘッドがなく、デッドロックの問題が発生する可能性は低くなります。読み取りが多く書き込みが少ない同時実行シナリオに適しています。追加のオーバーヘッドがないため、データベースのパフォーマンスを大幅に向上できます。

欠点:
楽観的同時実行制御は、書き込みが読み取りよりも多い同時実行シナリオには適していません。書き込みの競合が多く発生し、データの書き込みに複数の待機と再試行が発生するためです。この場合、そのオーバーヘッドは実際には悲観的ロックよりも高くなります。さらに、楽観的ロックのビジネス ロジックは悲観的ロックのビジネス ロジックよりも複雑です。ビジネス ロジックでは、失敗や再試行の待機を考慮する必要があり、他のサードパーティ システムによるデータベースへの直接的な変更を回避することはできません。

マルチバージョン同時実行制御

自然

Wikipedia: 多版型同時実行制御 (MCC または MVCC) は、データベース管理システムで一般的に使用される同時実行制御の一種であり、トランザクション メモリを実装するプログラミング言語でも使用されます。

楽観的同時実行制御と悲観的同時実行制御はどちらも、対応するトランザクションを遅延または終了することでトランザクション間の競合状態を解決し、トランザクションの直列化可能性を保証します。前の 2 つの同時実行制御メカニズムは、同時トランザクションの直列化可能性の問題を根本的に解決できますが、実際には書き込み競合の問題を解決しています。2 つの違いは、書き込み競合に関する楽観度の違いにあります (悲観的ロックも読み取り/書き込み競合を解決できますが、パフォーマンスは平均的です)。実際の使用では、データベースの読み取り要求は書き込み要求の数倍になります。読み取りと書き込みの同時実行の問題を解決できれば、データベースの読み取りパフォーマンスを大幅に向上させることができます。これが、マルチバージョン同時実行制御で実現できることです。

悲観的同時実行制御や楽観的同時実行制御とは異なり、MVCC は、読み取り/書き込みロックによって複数の長期読み取り操作が書き込み操作を枯渇させる問題、つまり読み取り/書き込み競合の問題を解決するように設計されています。 MVCC は、前の 2 つのメカニズムのいずれかと組み合わせて使用​​することで、データベースの読み取りパフォーマンスを向上させることができます。

データベースの悲観的ロックは、同時実行パフォーマンスの向上を考慮したものであり、一般的にはマルチバージョン同時実行制御を同時に実装します。 MySQL だけでなく、Oracle、PostgreSQL などの他のデータベース システムでも MVCC が実装されていますが、MVCC には統一された実装標準がないため、実装メカニズムはそれぞれ異なります。

一般的に、MVCC の出現は、パフォーマンスが低いために悲観的ロックを使用して読み取り書き込み競合問題を解決することに不満があるため、データベースによって提案されたソリューションです。

実装

MVCC は、特定の時点でのデータのスナップショットを保存することによって実装されます。各トランザクションで読み取られるデータ項目は、履歴スナップショットであり、スナップショット読み取りと呼ばれます。現在の読み取りとは異なり、スナップショット読み取りで読み取られるデータは最新のものではない可能性がありますが、スナップショット分離により、トランザクション全体で見られるデータは、開始時のデータ状態であることが保証されます。書き込み操作では既存のデータ項目は上書きされませんが、トランザクションがコミットされたときにのみ表示される新しいバージョンが作成されます。

現在の読み取りとスナップショットの読み取り

MySQL InnoDB の現在の読み取りとスナップショット読み取りとは何ですか?

共有モードでのロックの選択 (共有ロック)、更新の選択、更新、挿入、削除 (排他ロック) などの現在の読み取り操作はすべて現在の読み取りです。なぜ現在の読み取りと呼ばれるのでしょうか?つまり、レコードの最新バージョンを読み取ります。読み取り時には、他の同時トランザクションが現在のレコードを変更できないようにする必要があり、読み取られたレコードはロックされます。

スナップショット読み取りは、ロックなしの選択操作、つまりロックなしの非ブロッキング読み取りに似ています。スナップショット読み取りの前提は、分離レベルが非コミット読み取りやシリアル化レベルではないことです。これは、非コミット読み取りでは、現在のトランザクション バージョンに準拠するデータ行ではなく、常に最新のデータ行が読み取られるためです。シリアル化により、読み取られたすべての行がロックされます。

長所と短所

MVCC では、ロックなしでほとんどの読み取り操作を実行できます。この設計により、データの読み取り操作が簡単になり、パフォーマンスが向上し、条件を満たす行のみが読み取られるようになります。欠点は、レコードの各行ごとに追加のストレージ スペース、行のチェック作業、および追加のメンテナンス作業が必要になることです。

適用可能なシナリオ

悲観的ロック

読み取りと書き込みの競合や書き込みと書き込みの競合を解決するために使用されるロック同時実行制御は、読み取りよりも書き込みが多く、書き込みの競合が深刻な状況に適しています。悲観的ロックはデータの読み取り時にロックされるため、読み取りが多いシナリオでは頻繁なロックと長い待機時間が必要になります。深刻な書き込み競合の場合は、悲観的ロックを使用することでデータの一貫性を確保できます。高いデータ一貫性要件により、ダーティ リード、ファントム リード、非反復読み取り、ファースト クラス更新損失、セカンド クラス更新損失などの問題を解決できます。

楽観的ロック

書き込み競合を解決するロックフリー同時実行制御は、書き込みよりも読み取りが多い状況に適しています。書き込み操作の数が多いと、書き込み競合の可能性が高まり、ビジネス層が継続的に再試行する必要があり、システムパフォーマンスが大幅に低下するためです。データの一貫性要件は高くありませんが、非常に高い応答速度が必要です。ダーティリード、ファントムリード、非反復読み取りは解決できませんが、更新損失の問題を解決できます。

MVCC

読み取り書き込み競合を解決するロックフリーの同時実行制御を上記2つと組み合わせることで、読み取りパフォーマンスが向上します。

上記は、MySQL における楽観的ロック、悲観的ロック、および MVCC の包括的な分析の詳細な内容です。MySQL における楽観的ロック、悲観的ロック、および MVCC の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • MySQL の分離レベル、ロック、MVCC の紹介
  • MySQL ストレージ エンジン MyISAM と InnoDB の違いの概要
  • MySQLでデータテーブルを作成するときにエンジンMyISAM/InnoDBを設定する
  • MySQL InnoDB ストレージエンジンのメモリ管理の詳細な説明
  • MySQLのInnoDBストレージエンジンにおけるさまざまなロックの詳細な説明
  • MySQLのInnoDBストレージエンジンのデータページ構造の詳細な説明
  • MySQL ストレージ エンジン InnoDB と MyISAM
  • MYSQL データベース Innodb エンジン mvcc ロック実装原理

<<:  Vueはページdivボックスのドラッグアンドドロップソート機能を実装します

>>:  Docker用国産イメージウェアハウスの使い方

推薦する

Vueフォームバインディングとコンポーネントの詳細な説明

目次1. 双方向データバインディングとは1. データの双方向バインディングを実装する必要があるのはな...

React 構成 px 変換 rem メソッド

関連する依存関係をインストールするnpm i lib-flexible --save npm i p...

Vueのフィルターとディレクティブの詳細な説明

目次vueカスタムディレクティブグローバル指令ローカル指示使用フック関数(両方ともオプション)使用方...

Vue3 でマークダウン エディター コンポーネントを使用する方法

目次インストールコンポーネントのインポート基本的な使い方保存したマークダウンまたは HTML テキス...

仮想マシンの複製に関するVirtual Boxチュートリアル図

VMに慣れた後、BOXに切り替えるのは少し異なります。たとえば、コピーネットワークカードを2枚使って...

Vue コンポーネント (Vuex を含む) 間の値の転送に関する簡単な説明

目次父から息子へ:息子から父へ: Vuex を使用せずにコンポーネント間で値を渡す方法は、親から子、...

JavaScript でプライベート メンバーを作成する

目次1. クロージャを使用する2. ES6クラスを使用する3. ES2020提案を使用する4. We...

MySQL の遅いクエリ操作の例の分析 [有効化、テスト、確認など]

この記事では、MySQL のスロー クエリ操作について例を挙げて説明します。ご参考までに、詳細は以下...

独自の Docker イメージを作成して Dockerhub にアップロードする方法

1. まず、自分のdockerhubアカウントを登録します。登録アドレス: https://hub....

MySQLがOracleのnvlと同様の機能を持つことができるかどうかについての簡単な議論

isnullの代わりにifnullを使用するisnull は、null かどうかを判断するために使用...

UbuntuのVimにNERDTreeプラグインをインストールする詳細な手順

NERDTree は Vim 用のファイル システム ブラウザーです。このプラグインを使用すると、ユ...

よく忘れられがちな CSS のヒント 26 選

これは、よく使われるけれども忘れられがちな CSS 実装方法のコレクションです。抜けや追加があれば、...

CSSはラジオをクリックして2つの画像スタイルを切り替えますが、複数のラジオのうち1つだけをチェックできます。

クリックされたボタンには赤い画像スタイルを実装し、選択されていない他のボタンには灰色の画像スタイルを...

Linux で大容量メモリ ページを持つ Oracle データベースを最適化する方法

序文PC サーバーは今日まで発展を続け、パフォーマンスにおいて大きな進歩を遂げてきました。 64ビッ...

Linux の文字端末でマウスを使って赤い四角形を移動する方法

すべてがファイルです! UNIX はすでにそれを言っています。エリック・レイモンドはこう言いました。...