Redisの(8)分散ロック

アウトライン

記事は、アイデアの実現を紹介Redisの中に分布するだけでなく、機能が実現RedLockの使用を記載しています。

分散ロック・モチベーション

そこに複数のクライアントがあるが、一つだけが分散アーキテクチャを実行する権利を持っている場合には、分散ロックの使用を検討することができます。私たちは、最初のロックの目的は、順次実行を達成することである知っている必要があります。

RedLockデザイン

我々は2つの目的を満たしている必要があります。安全性と活動を守るために

  1. セキュリティ属性:その1つのクライアントだけにロックを取得するために同じ時間を確保するために、ミューテックス。
  2. A活性特性:ロックを取得したデッドロックの解放、クライアントのクラッシュまたはクラスタパーティションを解放することができます
  3. アクティブなプロパティB:フォールトトレランスは、限りのRedisノードのほとんどが生きているように、クライアントが取得する可能性があり、ロックを解除します。

なぜのみ達成フェイルオーバー・ベースでは十分ではありません

これは、我々は通常、高可用性を実現するために、マスタースレーブマスタースレーブレプリケーションを使用しているためであるが、以下があるかもしれません。

  1. クライアントAは、ロックを取得し(マスターラッチで取得したクライアントAに)マスターに
  2. キーへの書き込みがスレーブに送信される前に、マスターがクラッシュします。(オフダウンマスター、スレーブレプリケーション時間にマスターに書かれました)
  3. スレーブがマスタに昇格されます。(この時点でスレーブの継承では、元massterから新しいマスターになりました)
  4. 敵ダウン古いマスターは、その後、書き込み要求が成功を複製することはできないので、同じリソースAが既にその場合には、新しいマスターでロックclientBの取得、(!。SAFETY違反のロックを保持するために、クライアントBは、ロックを取得します2つのクライアントがロックを持っています)

RedLock実装

分散ロック単一Redisのノード

ロックを取得

SET RESOURCE_NAMEのmy_random_value NX PX 30000

my_randow_valueと有効期限:ここでは二つの主なものの使用を参照してください。このキーが存在し、かつ正確に私のようなmy_random_valueの間であれば、あなたが安全に行えます。各クライアントのmy_random_valueは、次のプロセスを表現するためにLUAを使用して、安全な方法でロックアップの解除を注文するために使用され、ユニークであります削除されました。

有効期限に関しては

クライアントが取得するとロックは、それがクラッシュした場合、成功している、またはネットワークのセグメント化のために(ネットワークパーティション)永遠もはやそれを引き起こして場所を取らなかったし、Redisのノードの通信、それはロックを保持し、他のクライアントされていたであろうあなたは、ロックを取得することはできません

もしredis.call( "取得"、KEYS [1])== ARGV [1]、その後
    redis.callを返します( "デル"、KEYS [1])
それ以外
    の戻り0 
終了

なぜこのmy_random_valueそれを使うのか?各クライアントのmy_random_valueあなたのために同じですか?次のシナリオを検討してください。

  1. クライアント1は、ロックの成功を取得します。
  2. 長い時間のためにブロックされた操作上のクライアント1。
  3. 有効期限に、ロックが自動的に解除されます。
  4. クライアント2は、同じリソースのロックに対応して取得します。
  5. 塞ぐからクライアント1つの回復は、クライアント2が保持しているロックを解放しました

実際には、このような状況は、リソースが他のクライアントによって保持されているかわからないの後に同じ操作でABAの問題CASのようなものです。

[OK]を、私たちは、その後、状況RedLock分散ロック分散型の実装を見てください。

分散ロック・プロセスがRedLockを概説しました

参考文献からの次の説明:

これは、N完全に独立Redisのノードに基づいています。

  1. (ミリ秒単位)現在の時刻を取得します。

  2. 順次順次N Redisのノードにロックを取得するための操作を行います。ランダムな文字列を含むmy_random_value同じRedisの単一のノード、フロントのロックを取得するために、この取得処理動作は、また、有効期限を(例えばPX 30000として、すなわち有効時間をロック)を含みます。アルゴリズムはまた、タイムアウト(時間切れ)を取得するロックの操作を実行し続けることができたときにRedisのノードが利用できないことを確認するためには、ロック(数十ミリ秒)の有効時間よりもはるかに小さいです。Redisの後にロックRedisのノードの障害を取得するには、クライアントはすぐに次のノードを試してみてください。ここで障害が、別のクライアントによって保持されたRedisのノードが利用できないような故障の任意のタイプ、またはRedisのノードのロックを含むべきである(注:Redlock説明Redisのは、ノードがここで使用できない場合を述べたが、それはまた)他の障害を含むべきです。

  3. どのくらいの時間の合計消費のロックを取得するプロセス全体の計算は、現在時刻と記録の第一工程の時間を減算することによって計算されます。クライアント・ノードが正常からRedisのを取得した場合、ほとんど(> = N / 2 + 1)ロック、ロック取得時間とロックより有効な合計消費時間(ロック有効時間)、次に時間に、クライアントは、最終的に得たこと成功したロック、そうでない場合、最終的に障害がロックを取得すること。

  4. 最終的な取得ロックが成功した場合、ロックの有効時間は、最初のロックの有効時間マイナス算出ロックステップ3を取得するために消費される時間に等しい、再計算されなければなりません。

  5. 最終的ロック獲得に失敗した場合は(おそらく取得時のためには、以下のRedisノードロックN / 2 + 1の数よりも、あるいは全体のロック取得プロセスが初期有効ロックを超える時間を消費し)、その後、クライアントはすぐにすべて通知しなければなりませんロックのRedisのノードを開始レリーズ操作(すなわち、RedisのLuaのスクリプトは、前述)。

私たちは、ノード時間がある場合はより高速で行く、単一の標準が存在しない時間の記録を見ることができ、

例としては、Notesを再起動します

A、B、C、D、Eの5つのノードの合計を仮定のRedis 次の一連のイベントが発生した想像:

  1. 1つの正常にロックされたクライアントA、B、Cは、正常にロックを獲得する(ただし、D及びEをロックされていません)。
  2. ノードCの再起動の崩壊が、Cで、クライアント1プラスロックが失われ、永続的なダウンしていません。
  3. ノードCは、再起動後、クライアント2が正常にロックを取得、C、D、Eをロック。

ロック失敗の問題に起因するノードの再起動の上記の分析として、常に可能があります。この問題に対処するために、それはまた、再起動遅延(遅延再起動)の概念を提案しantirez。言い換えれば、ノードがクラッシュした後、それは最初に、すぐに再起動しませんが、再起動するには、いくつかの時間のための待ち時間は、この時間は、ロック(ロック有効時間)の有効時間よりも大きくなければなりません。参加したロックの有効期限が切れる前に、この場合、ノードは、それが再起動後に既存のロックには影響しません、再起動します。

ロックリリースノート

ロックの最終リリース時に、antirezアルゴリズム記述に重点を置いて、クライアントは、すべてのノードにロックのRedisの解除操作を開始すべきです。つまり、このノードを見逃してはならないロックを解除するとき、成功せず、ノードにロックを取得しても、です。これはなぜでしょうか?クライアントノードのRedis Redisのに送信されたロック要求を取得し、このような状況を想像してみては首尾よく成功したSET操作を実施しているノードに到達したが、それは失われたクライアント応答パケットに返します。このクライアントは、タイムアウトのため失敗したロック要求を取得しているようだが、それはRedisの中でここにいるようだ、ロックが成功しています。ロックが解除されたときにそのため、クライアントは、要求を開始し、それらのRedisノードロックの障害のために時間を取得する必要があります。実際には、このケースでは、非同期通信モデルが発生する可能性があります。サーバーへの通信クライアントは正常ですが、反対の方向に問題があります。

マーティンの分析

https://martin.kleppmann.com/2016/02/08/how-to-do:マーティンKleppmannは、2016年2月8日で、この日、私は次のアドレスで、「どのように分散ロックを行うには」と呼ばれるブログを、公表しました-distributed-locking.html彼は前方redlockに関するいくつかの質問を置きます:

  • おそらくGCリードによるロック故障にRedLock
  • 時間に強く依存RedLockは、それ自体がセキュリティが十分ではありません。

分散ロック上のGCの影響

1297993-20200407095540783-1330354705.png

各地からの回復中に、クライアント1 GCの一時停止は、それが期限切れになった開催された、独自のロックを知らない場合、主要なロックの有効期限が切れる詰まりを実行する際に、GCスレッドは、それが共有リソース(画像上記にまだある、見ることができますストレージサービス)は、書き込みデータ要求を開始しましたが、今回は、ロックが実際にあるクライアント2は、両方のクライアントの要求、排他的な役割の競合(ロックの失敗)を書き込むことが可能であるので、保持しています。

それは破壊GCミューテックスロックの重要な要素があるので、それはGC環境はまだできません。記事のMはまた、メモリページフォルトとして、複雑なコンピュータシステムを作って、そのような現象につながる可能性があり、Mは、このような事件を避けるために、物事のトークンをフェンシング提案しました。

1297993-20200407100150240-1179496212.png

個人的に私はこれはmy_random_value役割トークンとRedLockフェンシングは、トークンの秩序を維持するがありますが、あなたと同じではありませんが、リソースが他のクライアントがロックされている識別することで、非常に奇妙な感じ。

セキュリティによって引き起こされる強力な時間的依存性

の説明から参考文献:

マーティンはRedlock障害(ロックを保持し、同時に2つのクライアントが)できるように、テキスト内のイベントのいくつかの配列を構築します。Redlockシステム(タイミング)でのオーバー依存呼ば例示するために、彼は最初(あると仮定5またはRedisのノードA、B、C、D、E)は、以下の例を与えます:

  • 1つのRedisのクライアントノードAから、B、Cが正常にロック(マジョリティノード)を取得しました。ネットワーク問題のため、D及びEは、障害と通信します。
  • ノードC上のクロックは、それがすぐに期限切れにロックのメンテナンスで、その結果、前方にジャンプ発生しました。
  • ノードC、D、Eから2 Redisのクライアントが正常にリソース(マジョリティノード)とのロックを取得しました。
  • クライアント1とクライアント2は今、彼らはロックを保持と思います。システムクロックが不正確になるとセキュリティRedlockの(安全性)クロックは、システムの性質に比較的強い依存性があるため、これが発生する可能性があります上記の理由は、アルゴリズムのセキュリティも保証することはできません。実際には、ときマーティンはここにいくつかの基本的な質問分散アルゴリズム、またはより良い非同期モデル(非同期モデル)に基づくアルゴリズムを分散する必要があるいくつかの一般的な感覚の問題を指摘することで、アルゴリズムのセキュリティはどのノートに頼るべきではありません(タイミング仮定)と仮定します。非同期モデルでは:プロセスは時間の任意の長さのために一時停止するかもしれませんが、メッセージは時間の任意の長さのために、ネットワーク内の遅れ、あるいは失われる可能性があり、システムクロックはどのような方法で間違っている可能性があります。良い分散アルゴリズムは、これらの要因は、このようなシステムクロック重大なエラーとして(でも、非常に極端な場合には、その安全性(安全性)に影響はないはずですが、と言うことですその活性(ライブネスプロパティ)を、影響を与える可能性があり)、アルゴリズムはのみの限定された期間は最大で結果を与えることはできませんが、間違った結果を与えるべきではありません。このようなアルゴリズムは、より多くの有名なパクシ、またはいかだのように、現実に存在しています。しかし、どうやらこの基準によると、その後、セキュリティのRedlockレベルは達成不可能です。

このセクションでは、前述したCAPのCPを思い出させてくれる、一貫性を維持するために、犠牲は唯一の可用性ことができます。

サプリメント

SETNX

SETNXコマンドを意味することは次のとおりです。[設定されていないが存在する場合]上記のアトミック実行を実現するためのLuaによって達成されるように設定し、SETNXがサポートされていない有効期限の設定になりますもう時間が、存在しないと言うだろう。

ロック解除原因の同時実行のタイムアウト

時間の短すぎる、他のクライアントがロックされて行うことができますが、有効期限が切れたためにリリースされたロックを実行していないが生じているため、クライアントがロックを取得することができる場合は、そのリソースへの2つのクライアントアクセスがあるでしょう。次のように解決策は以下のとおりです。

  • 有効期限を高めるために、あること、有効期限として実行時間を増やします
  • デーモンスレッドを増やし、ときに有効期限が切れるように有効期限を増やします

ロック再入

私たちは、Javaを知って、それが判断にデータ構造としてロックを再することができます:ThreadLocalのは、その後、Redisのは、それを達成する方法ですか?私たちは、Redissionが達成される方法を見て。

//そうでない場合には、本lock_key 
IF(redis.call( 'EXISTS'、KEYS [1])== 0) 次いで
    // lock_keyスレッド識別子1ロックするために設けられ
    redis.call( 'HSET'、KEYS [ 1]、ARGV [2]、1); 
    //設定期限
    redis.call( 'pexpire'、KEYS [1]、ARGV [1]); 
    戻りニル; 
    END; 
// lock_key電流が存在し、スレッド識別子がロックする場合スレッド識別
IF(redis.call( 'hexists'、KEYS [1]、ARGV [2])== 1)
    //インクリメント
    次いでredis.call( 'hincrby'、KEYS [1]、ARGV [2]、1 ); 
    //有効期限をリセット
    redis.call( 'pexpire'、KEYS [1]、ARGV [1]); 
    戻りゼロ、
    終了、
ロックが失敗した場合//、リターンロックが残り時間
戻りredis.call(「pttl 」、KEYS [1])。

HSETは、実際に、また、対応するデータを格納するためにThreadLocalハッシュテーブルを使用し、実現構造を使用して見ることができます。

ロック再試行をリリース

クライアントがロックを獲得する試行に再びロックを取得するために失敗した場合、その後、リトライ機能は、これを達成することができます:

  • 投票
  • 、買収が失敗した場合、ロック解除サブスクリプション情報をRedisのパブリケーション・サブスクリプションを使用してシグナリング、。図から、以下のようにプロセスがシグナル:https://xiaomi-info.github.io/2019/12/17/redis-distributed-lock/

1297993-20200407104331124-1808925956.png

概要

我々はそれに集中する必要がある時の各ノードに依存する実装の必要性をRedLock。いくつかの論争のRedLockについてのアイデアのredLockと実現についての記事は、最後のセクションでは、実装され、いくつかの補完的な機能のアイデアをまとめたもの。

参考資料

  • https://redis.io/topics/distlock(公文書)
  • http://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html(この問題のRedLock分散ロック)
  • http://zhangtielei.com/posts/blog-redlock-reasoning.html(必見)
  • https://www.one-tab.com/page/Wuz27GojRK6uiiBMgKcbwQ(ページ全集)

おすすめ

転載: www.cnblogs.com/Benjious/p/12651995.html