MySQLにおける分散ロックの考え方をDBの助けを借りて詳しく説明します

MySQLにおける分散ロックの考え方をDBの助けを借りて詳しく説明します

序文

スタンドアロン ロックであっても分散ロックであっても、共有データに基づいて現在の操作の動作を判断するのが原則です。単一のマシンの場合、RAM メモリは共有され、クラスターの場合は、Redis、ZK、DB などのサードパーティ コンポーネントの助けを借りて実現できます。 Redis と ZK は分散ロックの優れたサポートを提供し、基本的にすぐに使用できます。ただし、これらのコンポーネント自体は高可用性である必要があり、システムもこれらのコンポーネントに大きく依存する必要があるため、余分なコストがかかります。 DB は、システムのデフォルトで高可用性コンポーネントです。DB を使用して分散ロックを実装することは、複数のマシンでのスケジュールされたタスクの起動の制御や承認コールバックの処理など、一部の低頻度のビジネスにも適したソリューションです。この記事では、DB を使用して分散ロックを実装するためのシナリオとソリューションをいくつか紹介し、皆さんの参考になれば幸いです。

テーブルデザイン

まず、DB が依然としてシステムの中で最も脆弱なリンクであることは明らかです。したがって、設計時に圧力の問題を考慮する必要があります。つまり、アプリケーションで実装できるロジックは DB に実装しないでください。言い換えれば、DB が提供するロック機能はできるだけ使用しないでください。同時実行性の高いビジネスの場合は、DB ロックは避けてください。代わりに、Redis などのキャッシュ ロックを使用する方が効果的です。リスト 1 に示すように、テーブル内の唯一の制約は、lock_name、timestamp、version で構成される主キーです。これら 3 つのキーは、以下で悲観的ロックや楽観的ロックなどのビジネス シナリオを実装するために使用されます。

リスト1: 分散ロックテーブル構造

CREATE TABLE `lock` (
`lock_name` varchar(32) NOT NULL DEFAULT '' COMMENT 'ロック名',
`resource` bigint(20) NOT NULL COMMENT 'ビジネス主キー',
`version` int(5) NOT NULL COMMENT 'バージョン',
`gmt_create` datetime NOT NULL COMMENT '生成時間',
主キー (`lock_name`,`resource`,`version`)
)ENGINE=InnoDB デフォルト文字セット=utf8mb4;

悲観的ロックの実装

悲観的ロックビジネスには、次の 2 つの一般的な操作があります。


Aの場合:

シナリオ A では、あるマシンがロックを取得した後、他のマシンはキュー状態になります。ロックが解除された後にのみ続行できます。このアプリケーション レベルのソリューションは非常に面倒です。そのため、通常は DB が提供する行ロック機能、つまり xxx から xxx を選択して更新する機能が使用されます。シナリオ A は、一般的に在庫の増加や減少などビジネスに密接に関連しており、ビジネス オブジェクトを行ロックとして使用できます。このソリューションのロック圧力は基本的にデータベースにかかっていることに注意してください。ブロックされているスレッドが多すぎて操作に時間がかかる場合、最終的には大量のロック タイムアウトが発生します。

Bの場合:

シナリオ B (tryLock) では、特定のビジネスを例に挙げてみましょう。クラスターでは、各マシンにスケジュールされたタスクがありますが、ビジネスでは、通常、同時にスケジュールできるマシンは 1 台だけである必要があります。
解決策は、一意の主キー制約を使用して TaskA のレコードを挿入することです。デフォルトのバージョンは 1 です。挿入が成功すると、ロックが取得され、ビジネス操作を続行できます。このソリューションでは、マシンがハングアップするとデッドロックが発生するため、期限切れのロックを定期的にクリーンアップするためのスケジュールされたタスクも必要です。クリーニング ディメンションでは、lock_name に応じて異なる時間クリーニング戦略を設定できます。

スケジュールされたタスクのクリーンアップ戦略は、さらなる複雑さをもたらします。マシン A がロックを取得したが、CPU リソースの制約により、処理が遅くなったとします。このとき、スケジュールされたタスクによってロックが解除されるため、マシン B もロックを取得します。この場合、2 台のマシンが同時にロックを保持します。解決策は、タイムアウト期間をビジネス処理時間よりもはるかに長く設定するか、バージョン メカニズムを追加して楽観的ロックに変更することです。

ロックに挿入、lock_name='TaskA'、resource='ロックされたビジネス'、version=1、gmt_create=now() を設定
成功: ロックを取得します。 失敗: 操作を中止し、ロックを解除します。

楽観的ロックの実装

楽観的ロックのシナリオでは、特定のビジネスを例に挙げてみましょう。バックグラウンドシステムでは、ビジネス属性を格納するために大きなJSON拡張フィールドがよく使用されます。部分的な更新に関しては、まずそれらをクエリし、データをマージしてDBに書き込む必要があります。このプロセスに同時実行があると、データ損失が発生しやすくなります。したがって、データの一貫性を確保するためにロックが必要です。対応する操作を以下に示します。楽観的ロックの場合、デッドロックは発生しないため、ビジネスIDフィールドはここに直接保存され、各ビジネスIDに対応するレコードがあり、対応するタイマーによってクリアする必要がないことが保証されます。

select * from lock where lock_name='ビジネス名', resource='ビジネス ID';
存在しません: ロックに挿入して、lock_name='ビジネス名'、resource='ビジネス ID'、version=1 を設定します。
バージョンを取得: バージョン
ビジネス操作: データの取得、データのマージ、DB へのデータの書き戻し: update lock set version=version+1 where lock_name='business name' and resource='business id' and version= #{version};
書き戻し成功: 操作成功 書き戻し失敗: トランザクションをロールバックしてやり直します

楽観的ロックの書き込みが失敗すると、トランザクション全体がロールバックされます。したがって、楽観的ロックは書き込み競合が頻繁に発生するシナリオには適していません。大量のトランザクション ロールバックは DB に多大な負荷をかけ、最終的には特定の業務システムに影響を及ぼします。

要約する

分散ロックの原理は実際には理解しやすいのですが、特定のビジネス シナリオに最も適したソリューションを選択する方法が難しいのです。どのロック ソリューションを使用するかに関係なく、それはビジネスと密接に関連しています。つまり、完璧な分散ロック ソリューションは存在せず、現在のビジネスに最適なロック ソリューションのみが存在するのです。

さて、今回の記事は以上です。この記事の内容が皆さんの勉強や仕事に少しでも参考になれば幸いです。123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JavaはRedisson分散ロック実装原則を採用している
  • 分散ロックのコード例を実装するためのJavaプログラミングの再考
  • Redis分散ロックの正しい実装方法のまとめ
  • Redis 分散ロックの実装方法 (Redis 面接の質問)
  • springboot redis 分散ロック コード例
  • SpringBoot は Redisson を使用して分散ロック (セカンド キル システム) を実装します。
  • SpringBoot が Redisson を統合して分散ロックを実装する方法の例
  • Java Redis分散ロックの正しい実装の詳細な説明
  • Java redissonで実装された分散ロックの原理の詳細な説明

<<:  Vue のリスナーの基本的な使用例

>>:  MySQL マルチバージョン同時実行制御 MVCC の実装

推薦する

Vueのコンポーネントのprops属性について詳しく説明します

目次質問1: 小道具は具体的にどのように使用されますか?原理は何ですか?下を見る質問 2: 年齢に ...

MySQLのインデックス選択と最適化の詳細な説明

目次インデックスモデルB+ツリーインデックスの選択インデックスの最適化インデックスの選択性カバーイン...

MySQL 8.0 パスワード有効期限ポリシーの詳細な説明

MySQL 8.0.16 以降では、パスワードの有効期限ポリシーを設定できます。今日は、この小さな知...

Tomcat でのコネクタ構成

JBoss は Tomcat を Web コンテナとして使用するため、JBoss の Web コンテ...

Linux で環境変数 JAVA_HOME を変更/設定する方法について簡単に説明します。

1. 永久的な変更、すべてのユーザーに有効# vi /etc/プロファイル//キーボードの[Shi...

MySQL テーブルタイプ ストレージエンジンの選択

目次1. 現在のデータベース支出のストレージエンジンを表示する方法1:方法2: 2. ENGINE=...

Ubuntu で .sh ファイルを実行するいくつかの方法の違いについて簡単に説明します。

序文特に bash 環境では、スクリプトの実行方法によって結果が異なります。スクリプトを実行する方法...

@media レスポンシブ CSS を使用してさまざまな画面に適応する例

定義と使用@media クエリを使用すると、さまざまなメディア タイプに異なるスタイルを定義できます...

MySQL インデックス プッシュダウンを 5 分で学ぶ

目次序文インデックス プッシュダウンとは何ですか?インデックスプッシュダウン最適化の原理インデックス...

フロントエンドのパフォーマンス最適化 - フロントエンドエンジニアが話し合うべき問題点

はじめに<br />前回の記事「私の CSS アーキテクチャ コンセプト」では、公園で友...

ボタンをEnterキーに関連付けるjsコード

コードをコピーコードは次のとおりです。 <html> <ヘッド> <ス...

仮想マシンを作成し、VMware に Redhat Linux オペレーティング システムをインストールする (グラフィック チュートリアル)

VMware で仮想マシンを作成し、Redhat Linux オペレーティング システムをインスト...

JavaScriptで継承を実装するいくつかの方法

目次構造継承(callで実装)プロトタイプチェーン継承(プロトタイプチェーンの助けを借りて実装)複合...

Linux環境でglogログライブラリを使用する方法

Linuxライブラリを生成するLinux版はcentos7.3を使用し、コンパイルしてライブラリを生...

Win32 MySQL 5.7.27 のインストールと設定方法のグラフィックチュートリアル

MySQL 5.7.27のインストールチュートリアルは以下のように記録され、皆さんと共有されています...