Redis アプリケーション (Stars Chasing the Moon): 分散ロック

Redis アプリケーション (Stars Chasing the Moon): 分散ロック

[[431326]]

トピックの紹介

みなさんこんにちは、シャオロンです。

以前、「Redis をマスターするシリーズ」コラムの最初の記事「Redis の基礎 (基礎から始まる高層ビル): コアとなる基礎データ構造」を公開し、Redis、その内部構成、コアとなるデータ構造、一般的な使用シナリオについて簡単に紹介しました。まだ見ていない生徒は戻って見ることができます。

次回も引き続き、より深い理解へと導いてまいります。この記事では、Redis がよく使用されるシナリオ「Redis を使用して分散ロックを実践する」を紹介します。

同時実行の問題に遭遇した場合、通常、同時実行の問題を解決するためにロックを使用することは誰もが知っていると思います。

この時点で、生徒の中には「これはわかっている。 synchronized と Lock を使って実装すればいいのでは?」と言う人もいるかもしれません。

はい、その通りです。しかし、あなたの言うことは半分しか正しくありません。 「従来のスタンドアロン展開」の場合、排他制御には Java の並行処理関連の API (ReentrantLcok や synchronized など) を使用できます。

しかし、「分散システム」では、分散システムの「マルチスレッド」、「マルチプロセス」、「異なるマシンへの分散」により、元の単一マシン同時実行制御ロック戦略は無効になります。この問題を解決するには、分散ロックに依存する共有リソースへのアクセスを制御する「JVM 間排他メカニズム」が必要です。

ロックの本質を見抜く

私の意見では、すべてのロック自体は変数で表すことができます。

たとえば、「単一のマシン」上で実行されるマルチスレッド プログラムなどです。変数を取得します。変数が 0 の場合、どのスレッドもロックを取得していないことを意味します。変数が 1 の場合、スレッドがロックを取得したことを意味します。

ロック: スレッドはロック操作を呼び出し、変数が 0 かどうかを確認します。0 の場合は、どのスレッドもロックを取得していないことを意味します。ロックが取得されたことを示すために、変数は 1 に設定されます。 0 以外の場合は、他のスレッドが一時的にロックを使用していて、ロックを取得できなかったことを意味します。

ロック解除: 上記と同じ。

分散環境では、分散ロックは変数の形式でも理解できます。

ただし、単一のマシン上でロックを操作するスレッドとは異なり、分散シナリオでは、「ロック変数は共有ストレージ システムによって維持される必要があります。」この方法でのみ、複数のクライアントが共有ストレージ システムにアクセスしてロック変数にアクセスできます。それに応じて、「ロックのロックと解除の操作は、共有ストレージ システム内のロック変数値の読み取り、判断、および設定になります。」

「分散ロックの要件が満たされていることがわかります」:

  • 「ロック操作の原子性」: 分散ロックをロックおよび解放するプロセスには、複数の操作が含まれます。したがって、分散ロックを実装する場合は、これらのロック操作のアトミック性を確保する必要があります。
  • 「ロックの信頼性」: 共有ストレージ システムはロック変数を保存します。共有ストレージ システムに障害が発生したりクラッシュしたりすると、クライアントはロック操作を実行できなくなります。分散ロックを実装する場合、「共有ストレージシステムの信頼性」の確保を考慮した上で、「ロックの信頼性」を確保する必要があります。

上で、ロックを表すためにロック変数を使用できることを説明しましたが、これは「プレースホルダー」と考えることもできます。分散ロックでは、このピットを取り出して「共有」の場所に置く必要があり、全員が「共有」の場所からピットをチェックするだけです。

プレースホルダーは通常、setnx (存在しない場合は設定) 命令を使用して作成され、1 つのクライアントのみがその場所を占有できるようになります。先着順です。使用が終わったら、del コマンドを呼び出してトイレを解放します。

  1. //ロック
  2. > setnx ロックキー 1
  3. わかりました
  4. //ビジネスロジック
  5. >(その他の操作)
  6. //ロックを解除する
  7. > del lock_key

しかし、問題があります。ロジック実行の途中で例外が発生した場合、del 命令が呼び出されず、「デッドロック」が発生し、ロックが解放されなくなります。

したがって、ロックを取得した後、ロックに有効期限を追加します。これにより、途中で例外が発生した場合でも、指定された時間後にロックが自動的に解除されることが保証されます。

  1. //ロック
  2. > setnx ロックキー 1
  3. わかりました
  4. > ロックキー 5 の有効期限
  5. //ビジネスロジック
  6. >(その他の操作)
  7. //ロックを解除する
  8. > del lock_key

しかし、上記のロジックにはまだ問題が残っています。マシンの電源が切れたり手動で強制終了されたりしたために、setnx と expire の間でサーバー プロセスが突然クラッシュした場合、expire は実行されず、デッドロックが発生する可能性もあります。

この問題の根本は、setnx と expire がアトミック命令ではなく 2 つの命令であることです。トランザクションなどを使用して実行することも考えられますが、setnx がロックを取得しない場合は、expire は実行されないため、ここでは機能しません。

Redis 2.8 では、set コマンドに拡張パラメータが追加され、setnx コマンドと expire コマンドを一緒に実行できるようになり、分散ロックの問題が完全に解決されました。

  1. セット キー値 [EX 秒 | PXミリ秒] [NX]

上記の基本的な日常的な質問に加えて、次のような「考慮していない可能性のある質問」もあります。

タイムアウトの問題

Redis の分散ロックではタイムアウトの問題を解決できません。ロックとロック解除の間のビジネス ロジック実行時間が長すぎて、ロック タイムアウト制限を超えると、問題が発生します (つまり、ロックが期限切れになり、ビジネス ロジックが実行されません)。

この時点でロックの有効期限が切れているため、2 番目のクライアント B は再びロックを保持しますが、クライアント A がビジネス ロジックを実行するとすぐにロックが解除されます。クライアント B がロジックの実行を完了する前に、クライアント C がロックを取得します。この問題を回避するには、時間のかかるタスクには Redis 分散ロックを使用しないでください。

この問題に対処するには、異なるクライアントからのロック操作を区別できる必要があります。どうすればこれができるでしょうか?この問題に対処するには、コマンドにいくつかのトリックを追加する方法を見つけることができます。変数の値をロックする方法を考えることができます。

SETNX コマンドを使用してロックする方法では、ロックが成功したかどうかを示すためにロック変数の値を 1 または 0 に設定します。状態は 1 と 0 の 2 つだけであり、どのクライアントがロック操作を実行したかを示すことはできません。

したがって、ロック操作を実行するときに、「各クライアントにロック変数の一意の値を設定させる」ことができます。ここでの一意の値を使用して、現在の操作のクライアントを識別できます。

ロックを解除する場合、クライアントは現在の「ロック変数の値が自身の一意の識別子と等しいかどうか」を判断する必要があります。それらが等しい場合にのみロックを解除できます。こうすることで、誤ってロックを解除してしまうという問題がなくなります。

したがって、コマンドは次のように記述できます。

  1. //ロック、unique_valueはクライアントの一意の識別子として使用されます
  2. ロックキーの一意の値を設定するNX PX 5000

このうち、unique_value はクライアントの一意の識別子であり、ランダムに生成された文字列で表すことができます。 PX 5000 は、この期間中に例外が発生してクライアントがロックを解除できなくなることを防ぐために、lock_key が 5 秒後に期限切れになることを意味します。

各クライアントはロック操作で一意の識別子を使用するため、ロックを解除するときには、ロック変数の値がロック解除操作を実行するクライアントの一意の識別子と等しいかどうかを判断する必要があります。以下に示すように、Lua スクリプトを使用してアトミック性を確保できます。

  1. //ロックを解除し、誤って解除されないように unique_value が等しいかどうかを比較します
  2. redis.call( "get" ,KEYS[1])== ARGV[1]の場合 
  3. redis.call( "del" , KEYS[1])を返す
  4. それ以外 
  5. 0を返す
  6. 終わり 

再入性

再入可能性とは、スレッドがロックを保持したまま再度ロックを要求できることを意味します。ロックが同じスレッドによる複数のロックをサポートする場合、そのロックは再入可能になります。たとえば、Java 言語には再入可能ロックである ReentrantLock があります。

Redis 分散ロックが再入可能性をサポートする必要がある場合、クライアントの set メソッドをパッケージ化し、スレッドのスレッドローカル変数を使用して現在保持されているロックの数を保存できます。

ほとんどの人は尋ねないので、ここではあまり詳しく説明しません。興味があれば、ネットで調べたり、本を読んだりしてみてください。

課外活動の補足

上記の内容は、単一の Redis ノードに基づいて実装された分散ロックです。

「信頼性の高い分散ロック」を実装する場合、単一のコマンド操作だけに頼ることはできません。ロックおよびロック解除操作を実行するには、特定の手順とルールに従う必要があります。そうしないと、ロックが機能しない可能性があります。 「特定の手順とルール」とはどういう意味ですか?実は、これは分散ロックのアルゴリズムです。

ここでは、Redlock アルゴリズムの実行手順について簡単に説明します。 Redlock アルゴリズムの実装には、N 個の独立した Redis インスタンスが必要です。次に、3 つのステップでロック操作を完了します。

1. クライアントは現在時刻を取得する

2. クライアントは、各マスターインスタンスで順番にロックを取得しようとします。ロックを取得するプロセスでは、各ロック操作の失敗時間を短く設定します (10 秒のロックを取得する場合、各ロック操作の失敗時間は 5 ~ 50 ミリ秒に設定されます)。

これにより、クライアントが障害の発生したマスターと通信するのに時間がかかりすぎるのを防ぎ、高速障害を通じてクラスター内の他のノードとのロック操作をできるだけ早く完了することができます。

3. クライアントは、マスターとのロック取得プロセスで消費された時間を計算します。ただし、「クライアントがロックを取得するために消費した時間がロックの存続時間よりも短く、マスター ノードの半分以上でロックが取得された場合に限ります。」その場合にのみ、クライアントがロックを正常に取得したとみなされます。

4. ロックが取得された場合、「クライアントがタスクを実行するための時間枠は、ロックの存続時間からロックの取得に費やされた時間を差し引いた時間になります。」

5. クライアントが取得したロック数が半分未満の場合、またはロック取得時間がタイムアウトになった場合は、ロック取得に失敗したとみなされます。クライアントは、「2 番目のステップでマスター ノードのロックを正常に取得できなかった場合でも、すべてのマスター ノードのロックを解除しようとする必要があります。」

<<:  JVM の全体的な構造、実行プロセス、および 2 つのアーキテクチャ モデルの図解による説明。学びましたか?

>>:  疑似 SaaS ビジネス モデルがなぜこれほど普及しているのでしょうか?

推薦する

クラウドコンピューティング業界のアップグレードを支援するH3Cがクラウドネイティブ変革に関する洞察を共有

政策の恩恵とデジタル経済の加速的な発展に牽引され、クラウドネイティブ技術は急速に発展し、企業のデジタ...

raksmart: 月額 153 ドルから、香港クラスター、日本クラスター、シンガポールクラスター、米国クラスター、複数の C セグメントが利用可能

raksmartは米国の老舗データセンターとして、長年にわたりクラスタサーバ事業に従事しており、米国...

ブラック 5: Hostgator - 25% オフ / ホスティングは月額 1.24 ドルから

11月28日午前0時(米国中部時間、北京時間11月28日午後2時)から24時間、仮想ホスティングが2...

ガートナー: 中国でマルチクラウド モデルを成功させる方法

現在、中国政府は経済成長を加速させるために、クラウドコンピューティング技術を通じて産業界や企業にデジ...

初心者向けガイド: 請求サイクルの簡単な紹介/PayPal とクレジットカード支払いに関する注意事項

この記事では、Host Cat が初心者向けに支払いサイクルの問題について解説します。一般的に、海外...

ライブストリーミングeコマース、トップシェアを獲得

ライブストリーミングのトップインフルエンサーの失踪により、ライブストリーミング電子商取引業界が再び注...

Kubernetes プラグインを拡張するにはどうすればいいですか?これら6つの側面は重要です

Kubernetes プラグインまたは拡張機能は、Kubernetes スタックの重要な部分であり、...

QR コードのマーケティング時代はマーケティングのピークを作り出すことができるでしょうか?

QRコードといえば、皆さんもよくご存知だと思います。聞いたことはあるけど使い方が分からないという人も...

たった一晩でエントリー数が0から4万に急増?

ちょうど昨日、私のウェブサイトが Soso によってブロックされ、インデックスに登録されていた 40...

A5 マーケティング: マーケティングの最適化はいつ実行できるのでしょうか?

現在、インターネット上には、伝統的な企業が市場を発展・拡大したいと「呼びかける」記事がたくさんありま...

ビッグデータの孤立を打破: 主流の SaaS ベンダーが共同でオープン スタンダードを構築

10月27日、2017 iResearch A10 ビッグデータサミットにおいて「Intellige...

外部リンク構築におけるテキストリンクの最適化効果は無視できない

外部リンクの促進は、ウェブサイトの成長の主要な生命線の一つです。しかし、外部リンクの構築に関して、A...

レンガ職人はどうですか? Bricklayer の使い方は?初心者向けの質問に答える

レンガ職人はどうですか?レンガ積みのスピードはどうですか? BandwagonHost で Chin...

明らかにした!ウェブサイトの重みを素早く改善するにはどうすればいいですか?キーワードはすべて大丈夫ですか?

ウェブサイトの重量を迅速に改善するにはどうすればよいでしょうか。タイトルを見ただけで、多くの人がタイ...