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用国産イメージウェアハウスの使い方

推薦する

HTML要素を非表示にするいくつかの方法

1. CSSを使用するコードをコピーコードは次のとおりです。スタイル="display:n...

Nginx 構成検出サービスのステータスを実装する方法

1. チェックステータスモジュールがインストールされているかどうかを確認します。 [root@loc...

Linux 上でプロジェクトをリリースするために Tomcat を展開するプロセスにおけるさまざまな問題と解決策

プロジェクトをプロジェクトサイトのテスト環境にデプロイするJDK1.8トムキャット8.5 Maven...

Js クラスの構築と継承のケースの詳細な説明

JS のクラスの定義や継承は本当に多様なので、別のノートブックを開いて記録しておきます。意味オブジェ...

MySQL 匿名ログインでデータベースを作成できない問題の解決方法

よくある質問ユーザー ''@'localhost' によるデータベー...

Linux bash: ./xxx: バイナリ ファイルを実行できません エラー

今日、Ubuntu 用の小さなツールを顧客に送りましたが、ユーザーはそれを受け取った後、実行できませ...

MySQL における冗長インデックスと重複インデックスの違い

MySQL では、1 つの列に複数のインデックスを作成できます。意図的であるかどうかにかかわらず、M...

MySQL 5.7 および MySQL 8.0 でルートパスワードを変更する方法の概要

MySQL 5.7 バージョン:方法1: SET PASSWORDコマンドを使用するフォーマット: ...

2つのウェブサイトページ翻訳プラグインの共有

TranslateThis URL: http://translateth.is Google 翻訳...

ウェブページからテキスト透かしを削除する2つの簡単な方法

<br /> 特定の Web サイトを閲覧して、優れた Web ページを見つけた場合、そ...

CSS3+JS による虫眼鏡モードの完璧な実装の詳細説明

約 1 年前、私は「虫眼鏡効果を模倣するいくつかの方法の原理の分析」という記事を書きました。当時、自...

VMware および CentOS システムのインストール方法 - ルート パスワードをリセットする

今日のタスク1. Linuxディストリビューションの選択2.vmwareが仮想マシン(centos)...

Linux の cut コマンドの説明

Linux や Unix の cut コマンドは、ファイルの各行から一部を切り取って標準出力に出力す...

JSは賞金の重さに基づいて当選確率を計算します

目次1. シナリオ例1.1. 抽選の賞品名を設定する1.2. 各賞の重みを設定する1.3. ラッキー...