Redisのみをロックする必要があります

Redisロックと言えば、次の3つが最も頻繁に使用される単語と見なされます。

  • Setnx
  • RedLock
  • Redisson

 

Setnx

 

現在一般的に参照されているSetnxコマンドは、Redis setnx keyvalueコマンドだけを参照しているわけではありません。

 

一般に、RedisでのSetコマンドとNXパラメーターの使用を指します。Setコマンドは現在、非常に多くのオプションパラメーターをサポートしています。

SET key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]

 

もちろん、この記事ではAPIを黙って書くつもりはありません。基本的なパラメーターはまだ不明なので、公式Webサイトにジャンプできます。

上の図は、作者が描いたSetnxの一般原理です。主に、キーが存在しないという特徴に依存して正常に設定されます。プロセスAがロックを取得します。ロックのキーが削除されない場合、プロセスBは自然に失敗します。ロックを取得します。

 

では、なぜPX30000を使用してタイムアウト期間を設定するのでしょうか。プロセスAが無理で、ロックが解除されていないのではないかと思います。ロックが解除されると、ロックが直接解除され、システム内の誰もロックを取得できなくなります。

それでも、絶対確実性の保証はありません。プロセスAが不合理であり、操作ロック内のリソースが作成者によって設定されたタイムアウト期間を超えた場合、他のプロセスがロックを取得します。プロセスAが戻ったとき、答えは、に示すように、他のプロセスのロックを削除することです。図:

今の写真では、T5時間がロックタイムアウトに変更されています。これはRedisによって解放されます。

 

プロセスBはT6で問題なくロックを取得し、しばらくはかかりません。プロセスAは操作を終了し、Delを返してロックを解除します。

 

プロセスBの操作が完了し、ロックが解除されたとき(図の時間T8):

 

実際、ロックが見つからないことは悪くありません。プロセスCがT7で正常にロックされるようになると、プロセスBはプロセスCのロックを解放します。

 

類推により、プロセスCはプロセスD、プロセスD ...のロックを解除する場合があります(人形は禁止されています)。具体的な結果は不明です。

 

そのため、Setnxを使用する場合、キーが主な機能ですが、値をアイドル状態にすることはできません。一意のクライアントIDを設定するか、UUIDなどの乱数を使用できます。

 

ロックを解除するときは、最初に値を取得して、それが現在のプロセスによって追加されたロックであるかどうかを判断してから、削除します。偽のコード:

String uuid = xxxx;
// 伪代码,具体实现看项目中用的连接工具
// 有的提供的方法名为set 有的叫setIfAbsent
set Test uuid NX PX 3000
try{
// biz handle....
} finally {
    // unlock
    if(uuid.equals(redisTool.get('Test')){
        redisTool.del('Test');
    }
}

 

今回は安定しているように見えますか?それどころか、今回は問題がより明白になります。finallyコードブロックでは、GetとDelはアトミック操作ではなく、プロセスのセキュリティ問題がまだあります。

 

なぜそんなに多くの質問があるのですか?2つの理由があります:

  • 不利な点を明確にすることによってのみ、私たちはそれをより良く改善することができます。
  • 上記の最後のコードは、今でも多くの企業で使用されています。

 

大小のアイテムのパラドックス:

大企業は標準を実装していますが、中小企業や小プロジェクトは厳密ではありませんが、並行性は高くなく、問題の可能性は大企業と同じくらい低くなっています。

 

 

 

次に、ロックを解除する正しい姿勢の1つは、Luaスクリプトを使用してRedisのeval / evalshaコマンドを実行することです。

-- lua删除锁:
-- KEYS和ARGV分别是以集合方式传入的参数,对应上文的Test和uuid。
-- 如果对应的value等于传入的uuid。
if redis.call('get', KEYS[1]) == ARGV[1] 
    then 
    -- 执行删除操作
        return redis.call('del', KEYS[1]) 
    else 
    -- 不成功,返回0
        return 0 
end

 

Luaスクリプトで原子性を確保する理由はもう少し一般的です。Luaで花を書いても、実行はコマンド(eval / evalsha)によって実行されます。コマンドが実行されない場合、他のクライアントはそれを見ることができません。

 

それで、それはとても面倒なので、より良いツールはありますか?Redissonについて話しましょう。

 

Redissonを紹介する前に、著者は、現在のSetnxのデフォルトがSetnxコマンドを直接参照するのではなく、NXパラメーターを使用してSetコマンドを参照する理由を簡単に説明します。

 

Redisのバージョンは2.6.12より前であるため、SetはNXパラメーターをサポートしていません。ロックを完了するには、次の2つのコマンドが必要です。

1. setnx Test uuid
2. expire Test 30

 

つまり、キーの入力と有効期間の設定は2つの別々のステップであり、理論的には実行直後に1になり、プログラムがハングし、原子性は保証されません。

 

しかし、早くも2013年、つまり7年前にRedisはバージョン2.6.12をリリースし、公式Webサイト(Setコマンドページ)にも「SETNX、SETEX、PSETEXは将来のバージョンで非推奨になり、完全に削除される可能性がある」と記載されています。

 

著者はかつて大物の記事を読んだことがあります。その中には、初心者をガイドする小さなインタビュールーチンがあります。特定のテキストは忘れられています。おそらく次のことを意味します。Redisロックに関しては、最初にSetnxから始めることができます。ゆっくりと引き出します。Setコマンドにパラメータを追加して、自分の知識を反映させることができます。

 

あなたが運命によってこの記事を読み、このルーチンを学んだならば、この記事の著者として、私はリマインダーを追加したいと思います:あなたの労働年に注意を払ってください!まず、公式サイトで破棄されそうなコマンドに答えてから、7年前のセットコマンドの「新機能」を紹介します。卒業したばかりの人がそう言ったら、インタビュアーは行ったと思います。使って。

あなたはインタビュアーをします、インタビュアーもあなたをします。  


--vt・Wozkistock

 

Redisson

 

RedissonはJavaのRedisクライアントの1つであり、Redisの操作を容易にするいくつかのAPIを提供します。

 

しかし、Redissonクライアントは少し強力です。著者は公式ウェブサイトの写真の一部のみをカットしました。

この機能リストは多すぎると言えます。JUCパッケージでいくつかのクラス名を見たことがありますか?Redissonは分散バージョンの作成を支援してくれました。

 

たとえば、AtomicLongは、RedissonAtomicLongを直接使用するだけで、クラス名を覚えておく必要もありません。これは非常にユーザーフレンドリーです。

 

ロックは氷山の一角に過ぎず、Wikiページから、マスタースレーブ、センチネル、クラスター、その他のモードをサポートしています。もちろん、シングルノードモードは確実にサポートされています。

 

この記事はまだロックに焦点を当てており、他の記事は紹介されません。Redissonの一般的なロック実装のソースコードは主にRedissonLockです。そのソースコードを見たことがない人は、見てみたいと思うかもしれません。

 

ソースコードのロック/リリースロック操作はすべてLuaスクリプトで実行され、パッケージは非常に完全で、箱から出してすぐに機能します。

ここに小さな詳細があります。ロックはSetnxを使用して実現できます。Luaスクリプトを使用する必要はありませんか?

 

著者はまたそれについて非常に厳密に考えました:そのような強力なものはどうやって無駄なコードを書くことができますか?

 

実際、作者は詳しく調べました。ロックとロック解除のLuaスクリプトは、ロックの再入可能性を含め、非常に包括的です。これは非常に思慮深いと言えます。テスト用のコードも作成しました。

確かにJDKのReentrantLockと同じくらいスムーズなので、Redissonは非常にうまく実装されていますが、RedLockとは何ですか?

 

RedLock

 

 

RedLockの中国語は文字通り翻訳されており、RedLockと呼ばれています。レッドロックはツールではありませんが、Redisによって公式に提案された分散ロックアルゴリズムです。

 

導入されたばかりのRedissonでは、RedLockバージョンのロックが実装されました。つまり、getLockメソッドに加えて、getRedLockメソッドもあります。

 

著者はおそらく赤い錠の理解を引き出しました:

Redisの高可用性デプロイメントに精通していない場合は、問題ありません。RedLockアルゴリズムには複数のインスタンスが必要ですが、これらのインスタンスは独立してデプロイされ、マスターとスレーブの関係はありません。

 

RedLockの作成者は、independentを使用する理由は、Redis非同期レプリケーションによって引き起こされるロック損失を回避するためであると指摘しました。たとえば、マスターノードが来ず、データがスレーブノードに設定されたばかりの場合、ハングします。

 

大物はレバーが得意で、毎日極端な状況を考えていると思う人もいますか。実際、高可用性であり、小数点以下の桁の99.999 ...%です。

 

上の簡単な図に戻ると、赤いロックアルゴリズムは、2N + 1ノードが正常にロックされている限り、ロックが取得されたと見なされ、ロック解除時にすべてのインスタンスがロック解除されると考えています。

 

プロセスは次のとおりです。

  • 5つのノードから順番にロックを要求する
  • 特定のタイムアウト期間に基づいてノードをスキップするかどうかを推測します
  • 3つのノードが正常にロックされ、費やされた時間がロックの有効期間よりも短い
  • ロックが成功したことを確認します

 

つまり、ロックが30秒で期限切れになり、3つのノードをロックするのに31秒かかったとすると、ロックが失敗したのは当然です。

 

これは単なる例です。実際、各ノードをそれほど長く待つ必要はありません。公式Webサイトに記載されているように、有効期間が10秒であると仮定すると、1回のRedisインスタンス操作のタイムアウト期間は5〜50である必要があります。ミリ秒(時間単位に注意)。

 

有効期間を30秒に設定し、図で2つのRedisノードがタイムアウトしたとします。次に、ロックを正常にロックしたノードは合計3秒かかったため、ロックの実際の有効期間は27秒未満です。

 

つまり、3つのインスタンスを正常にロックするための3秒が差し引かれ、タイムアウトのRedisインスタンスを待機する合計時間も差し引かれます。これを見て、あなたはこのアルゴリズムについていくつかの質問があるかもしれません、そしてあなたは一人ではありません。

 

Redisの公式ウェブサイトでRedLockの説明を振り返ると、この説明ページの下部に、RedLockに関する有名な妖精の戦いが表示されます。

MartinKleppmannとAntirezの間のRedLockの議論。1人は高度な資格を持つ分散型アーキテクトであり、もう1人はRedisの父です。

 

公式にリンクされた人々は最も致命的です。冗談ですが、公式ウェブサイトに質問を掲載できれば、それは価値のあるものに違いありません。

 

したがって、プロジェクトでRed Lockを使用する場合は、Red Lockの紹介に加えて、さらに2つの記事を読むことをお勧めします。

  • MartinKleppmannによる質問投稿

  • アンティレスの反撃ポスト

おすすめ

転載: blog.csdn.net/baidu_39322753/article/details/104943302