【31-Redis分布ロック進化史】
9965 ワード
【博文総目録>>>】
Redis分布ロック進化史
ここ2年来、マイクロサービスはますます人気があり、ますます多くの応用が分布式環境に配置されている.分布式環境では、データ整合性は従来から注目され、解決しなければならない問題であり、分布式ロックも広く使用されている技術となり、よく使われる分布式実現方式はRedis、Zookeeperであり、その中でRedisベースの分布式ロックの使用はより広範である.
しかし、仕事とネット上で各バージョンのRedis分布式ロックの実現を見たことがあります.各実現にはいくつかの厳密ではないところがあります.コードに含まれている可能性もあります.分布式ロックを正しく使用できないと、深刻な生産環境の故障を引き起こす可能性があります.本文は主に現在直面している各種分布式ロックとその欠陥を整理しました.適切なRedis分散ロックの選択方法を提案した.
各バージョンのRedis分散ロック
ここ2年来、マイクロサービスはますます人気があり、ますます多くの応用が分布式環境に配置されている.分布式環境では、データ整合性は従来から注目され、解決しなければならない問題であり、分布式ロックも広く使用されている技術となり、よく使われる分布式実現方式はRedis、Zookeeperであり、その中でRedisベースの分布式ロックの使用はより広範である.
しかし、仕事とネット上で各バージョンのRedis分布式ロックの実現を見たことがあります.各実現にはいくつかの厳密ではないところがあります.コードに含まれている可能性もあります.分布式ロックを正しく使用できないと、深刻な生産環境の故障を引き起こす可能性があります.本文は主に現在直面している各種分布式ロックとその欠陥を整理しました.適切なRedis分散ロックの選択方法を提案した.
各バージョンのRedis分散ロック
tryLock(){
SETNX Key 1
EXPIRE Key Seconds
}
release(){
DELETE Key
}
このバージョンは最も簡単なバージョンであり、出現頻度の高いバージョンでもあるはずです.まず、ロックに期限切れの操作を追加するのは、サービスの再起動や異常によってロックが解放されなくなった後、ロックが解放されないことを避けるためです.
このシナリオの1つの問題は、1つのRedisリクエストが発行されるたびに、1つ目のコマンドが実行された後に例外が適用されたり、再起動されたりすると、ロックが期限切れにならないことです.1つの改善策は、Luaスクリプト(SETNXとEXPIREの2つのコマンドを含む)を使用することですが、Redisが1つのコマンドのみを実行した後にcrashが発生したり、プライマリ・スレーブ・スイッチが発生したりしても、ロックが期限切れになっていないため、
もう一つの問題は、多くの学生が分散ロックを解放する過程で、ロックが成功するかどうかにかかわらずfinallyでロックを解放することであり、これはロックの誤った使用であり、この問題は後続のV 3になる.バージョン0で解決.
ロックが解放されない問題に対する解決策の1つは、GETSETコマンドに基づいて実現される
考え方:
注意:このバージョンではEXPIREコマンドを削除し、Valueタイムスタンプ値で期限切れを判断するように変更しました
質問:
tryLock(){
SETNX Key 1 Seconds
}
release(){
DELETE Key
}
Redis 2.6.12以降、SETNXは有効期限パラメータを追加し、2つのコマンドが原子性を保証できないという問題を解決しました.しかし、次のシーンを想定します.
大まかなフローチャート
問題:
tryLock(){
SETNX Key UnixTimestamp Seconds
}
release(){
EVAL(
//LuaScript
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
)
}
この方式は、Valueをタイムスタンプとして指定する、ロックを解除する際にロックのValueがロックを取得するValueであるか否かをチェックすることにより、V 2を回避する.0バージョンで述べたC 1は、C 2が保持するロックの問題を解放した.また,ロックを解除する際には複数のRedis操作が関与し,Check And Setモデルの同時問題を考慮してLuaスクリプトを用いて同時問題を回避する.
問題:
また、分散環境での物理クロックの一貫性が保証されていないため、UnixTimestampの重複問題も存在する可能性がありますが、まれに発生する可能性があります.
tryLock(){
SET Key UniqId Seconds
}
release(){
EVAL(
//LuaScript
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
)
}
Redis 2.6.12後のSETは同様に1つのNXパラメータを提供し、SETNXコマンドと同等である.公式文書では、後のバージョンがSETNX、SETEX、PSETEXを削除する可能性があることを注意し、SETコマンドで代替し、もう1つの最適化は、タイムスタンプの代わりに増加した唯一のUniqIdを使用してV 3を回避することである.0クロックの問題について説明します.
このスキームは現在最良の分散ロックスキームであるが,Redisクラスタ環境で依然として問題がある場合:
Redisクラスタのデータ同期は非同期であるため、Masterノードがロックを取得した後にデータ同期が完了していない場合、Masterノードcrashが新しいMasterノードでもロックを取得できると仮定し、複数のClientが同時にロックを取得する
分散型Redisロック:Redlock
V3.1のバージョンは単一のインスタンスのシーンでのみ安全であり、どのように分布式Redisのロックを実現するかについて、国外の分布式専門家が激しい議論をしたことがある.antirezは分布式ロックアルゴリズムRedlockを提案した.distlockの話題の下でRedlockの詳細な説明を見ることができる.以下はRedlockアルゴリズムの中国語の説明(引用)である.
N個の独立したRedisノードがあると仮定する
しかしMartin Kleppmannはこのアルゴリズムに疑問を提起し,fencing tokenメカニズムに基づいているべきであることを提案した(リソースを操作するたびにtoken検証が必要である).
次にantirezはMartin Kleppmannの疑問に答え、期限切れのメカニズムの合理性と、実際のシーンで停止問題が発生して複数のClientが同時にリソースにアクセスした場合の処理を示した.
Redlockの問題に対して,Redisに基づく分散ロックは果たして安全なのか,詳細な中国語の説明を与え,Redlockアルゴリズムに存在する問題を解析した.
まとめ
SETNXバージョンに基づくRedis単一インスタンス分散ロックも、Redlock分散ロックも、次の特性を保証するために使用されます.
したがって、分散ロックの開発または使用中に安全性と活性を保証し、予測不可能な結果を回避しなければならない.
また、各バージョンの分散ロックには、ロックの使用上、ロックの実用的なシーンに対して適切なロックを選択する問題があります.通常、ロックの使用シーンには次のような問題があります.
Efficiency(効率):操作を完了するために1つのClientだけが必要で、繰り返し実行する必要はありません.これは緩やかな分布式ロックで、ロックの活性を保証するだけでいいです.
Correctness(正確性):複数のClientは厳格な反発性を保証し、同時にロックを保持したり、同じリソースを同時に操作したりすることは許されません.このようなシーンでは、ロックの選択と使用がより厳しく、ビジネスコード上でできるだけべき乗などを行う必要があります.
Redis分散ロックの実装にはまだ多くの問題が解決を待っています.これらの問題を認識し、Redis分散ロックを正しく実装し、作業中に分散ロックを合理的に選択し、正しく使用する方法を明確にする必要があります.