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 の実装

推薦する

MySQLインストール後のデフォルトデータベースの役割の詳細な説明

MySQL を学習すると、インストール後にいくつかのデフォルトのデータベースが付属していることに気付...

Linux で毎日データベースの自動バックアップを設定する方法

この記事では、Centos7.6 システムと Oracle11g を例に挙げます。 1. まずデータ...

DockerでRedisを使用するための詳細な手順

1. はじめにこの記事では、Docker を使用して Redis を探索する方法を説明します。 Do...

インターフェース設計の10の一般的なルール

<br />これは私がずっと前に集めた記事です。皆さんの参考のために共有したいと思います...

MySQLデータベースがNULLを可能な限り避ける理由

MySQL の多くのテーブルには、NULL が列のデフォルト属性であるため、アプリケーションが NU...

Vueプロジェクトでパラメータジャンプ機能を実装する

ページの説明:​ メインページ: 名前 —> shishengzuotanhuichaxun ...

Web 上の要素を非表示にする方法とその利点と欠点

ソースコードの例: https://codepen.io/shadeed/pen/03caf6b36...

vue3+threejs を使用して iView 公式サイトのビッグウェーブ特殊効果の例を模倣する

目次序文1. レンダリング2. コード3. 背景画像素材要約する序文Threejs は、Web ベー...

Sublime TextがUbuntuで中国語を入力できない問題の最も簡単な解決策

崇高なSublime Text はコード エディター (Sublime Text2 は有料ソフトウェ...

ブートストラップ学習体験のまとめ - CSS スタイル デザイン共有

プロジェクトのニーズにより、ブートストラップ フレームワークを慎重に学習する予定です。以前から少しは...

テキストエリアのテキスト入力領域に改行を実装する方法

textarea 入力領域でテキストを折り返す場合は、<br/> と入力すると <...

MyCat を使用して Linux で MySQL マスター/スレーブの読み取り/書き込み分離を実装する方法

目次Linux - MyCat を使用して MySQL マスター スレーブの読み取り書き込み分離を実...

MySQLがlocalhost経由でデータベースに接続できない問題に対する完璧な解決策

問題:あるサーバー上の PHP プログラムは、localhost アドレス経由でデータベースに接続で...

単一の MySQL テーブルで数千万のデータを処理するアイデアを共有する

目次プロジェクトの背景改善案データ特性を観察するマルチプロセスアイデアの要約データ処理スキルプロジェ...

jQuery プロジェクトで重複送信を防ぐ方法

新しいプロジェクトでは、axios によって重複した送信を防ぐことができますが、古いプロジェクト (...