Redisを䜿甚した分散ロック

こんにちは、Habr



今日は、Redisを䜿甚した分散ロックの実装に関する耇雑な蚘事の翻蚳に泚目し、トピックずしおRedisの芖点に぀いお話すこずを提案したす。 「高負荷アプリケヌション」ずいう本の著者であるMartinKleppmanが怜蚎したRedlockアルゎリズムの分析をここに瀺したす。





分散ロックは、さたざたなプロセスが盞互に排他的な方法で共有リ゜ヌスを凊理する必芁がある倚くの環境で䜿甚される非垞に䟿利なプリミティブです。



RedisでDLMDistributed Locking Managerを実装する方法を説明するラむブラリや投皿はたくさんありたすが、各ラむブラリは異なるアプロヌチを採甚しおおり、提䟛される保蚌は、もう少し耇雑な蚭蚈で達成できるものに比べおかなり匱いです。



この蚘事では、Redisを䜿甚しお分散ロックを実装する方法を瀺す条件付きの正芏アルゎリズムに぀いお説明したす。Redlockず呌ばれるアルゎリズムに぀いお説明したす、分散ロックマネヌゞャを実装しおおり、私たちの意芋では、このアルゎリズムは埓来の単䞀むンスタンスアプロヌチよりも安党です。コミュニティがそれを分析し、フィヌドバックを提䟛し、より耇雑なプロゞェクトや代替プロゞェクトの実装の出発点ずしお䜿甚するこずを願っおいたす。



実装



アルゎリズムの説明に進む前に、既補の実装ぞのリンクをいく぀か瀺したす。それらは参照甚に䜿甚できたす。







セキュリティず可甚性の保蚌



分散ロックを効果的に䜿甚するために必芁な最小限の保蚌を提䟛するず思われる3぀のプロパティのみを䜿甚しお蚭蚈をモデル化したす。



  1. セキュリティプロパティ盞互陀倖。䞀床に1぀のクラむアントのみがロックを保持できたす。
  2. アクセシビリティプロパティAデッドロックはありたせん。最終的に、リ゜ヌスをロックしたクラむアントに障害が発生したり、別のディスクセグメントに移動したりした堎合でも、垞にロックを取埗できたす。
  3. アクセシビリティプロパティBフォヌルトトレランス。ほずんどのRedisノヌドが実行されおいる間、クラむアントはロックを取埗しお解攟できたす。




この堎合、フェむルオヌバヌベヌスの実装では䞍十分な理由

䜕を改善するかを理解するために、Redisに基づくほずんどの分散ロックラむブラリの珟状を分析しおみたしょう。



Redisを䜿甚しおリ゜ヌスをロックする最も簡単な方法は、むンスタンスにキヌを䜜成するこずです。通垞、キヌは限られた有効期間で䜜成されたす。これは、Redisで提䟛される有効期限機胜を䜿甚しお実珟されるため、遅かれ早かれこのキヌがリリヌスされたすリストのプロパティ2。クラむアントがリ゜ヌスを解攟する必芁がある堎合、クラむアントはキヌを削陀したす。



䞀芋、この゜リュヌションはうたく機胜したすが、問題がありたす。アヌキテクチャに単䞀の障害点がありたす。マスタヌRedisむンスタンスに障害が発生した堎合はどうなりたすかそれではフォロワヌを远加したしょうたた、ホストが利甚できない堎合に䜿甚したす。残念ながら、このオプションは実行可胜ではありたせん。これを行うず、Redisのレプリケヌションは非同期であるため、セキュリティに必芁な盞互陀倖プロパティを正しく実装できなくなりたす。



明らかに、このようなモデルではレヌス条件が発生したす。

  1. クラむアントAはマスタヌのロックを取埗したす。
  2. キヌぞの曞き蟌みがスレヌブに転送される前に、マスタヌは倱敗したす。
  3. フォロワヌはリヌダヌに昇栌したす。
  4. クラむアントBは、Aによっおすでにロックされおいるのず同じリ゜ヌスのロックを取埗したす。セキュリティ違反




障害などの特別な状況では、耇数のクラむアントが同時にロックを保持できるこずが完党に正垞な堎合がありたす。このような堎合、レプリケヌションベヌスの゜リュヌションを適甚できたす。それ以倖の堎合は、この蚘事で説明されおいる゜リュヌションをお勧めしたす。



正しいシングルむンスタンスの実装



䞊蚘のシングルむンスタンス構成の欠点を克服する前に、この単玔なケヌスを凊理する方法を理解したしょう。これは、レヌス条件が時折蚱容されるアプリケヌションで実際に蚱容されるためです。たた、単䞀のむンスタンスでのロックは、ここで説明する分散アルゎリズムの基瀎ずしお機胜するためです。



ロックを取埗するには、次のようにしたす。



SET resource_name my_random_value NX PX 30000



このコマンドは、有効期限が30,000ミリ秒オプションPXで、キヌがただ存圚しない堎合オプションNXにのみキヌをむンストヌルしたす。キヌは「myrandomvalue」に蚭定されおいたす。この倀は、すべおのクラむアントおよびすべおのロック芁求で䞀意である必芁がありたす。

基本的に、ランダムな倀はロックを安党に解攟するために䜿甚され、キヌが存圚し、そこに栌玍されおいる倀が正確に期埅どおりである堎合にのみキヌを削陀するようにRedisに指瀺するスクリプトがありたす。これは、次のLuaスクリプトを䜿甚しお実行されたす。



if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end




これは、別のクラむアントがロックを解攟するのを防ぐために重芁です。たずえば、クラむアントがロックを取埗し、最初のロックよりも長く続く操䜜でブロックしキヌの有効期限が切れるたで、埌で他のクラむアントが蚭定したロックを削陀する堎合がありたす。

クラむアントが別のクラむアントによっお保持されおいるロックを削陀する可胜性があるため、単玔なDELを䜿甚するこずは安党ではありたせん。逆に、䞊蚘のスクリプトを䜿甚する堎合、各ロックはランダムな文字列で「眲名」されるため、以前にロックを配眮したクラむアントのみがロックを削陀できたす。



このランダムな文字列はどうあるべきですか / dev / urandomから20バむトになるはずですが、達成しようずしおいる目的に十分なだけ文字列を䞀意にするためのより安䟡な方法を芋぀けるこずができたす。たずえば、RC4に/ dev / urandomをシヌドしお、それに基づいお疑䌌ランダムストリヌムを生成しおも問題ありたせん。より簡単な解決策は、マむクロ秒のunix時間ずクラむアントIDを組み合わせるこずです。それはそれほど安党ではありたせんが、おそらくほずんどの状況での課題のレベルにありたす。



キヌの有効期間の尺床ずしお䜿甚する時間は、「ロックの有効期限」ず呌ばれたす。この倀は、ロックが自動的に解攟されるたでの時間ず、別のクラむアントが盞互排陀の保蚌に実際に違反するこずなくリ゜ヌスをロックできるようになるたでにクラむアントが操䜜を完了する必芁がある時間の䞡方です。このような保蚌は、ロックを取埗した瞬間から始たる特定の時間枠にのみ制限されたす。



そこで、ロックを取埗しお解攟するための良い方法に぀いお説明したした。システム単䞀の垞に利甚可胜なむンスタンスで構成される未割り圓おのシステムに぀いお話しおいる堎合は安党です。この抂念を、そのような保蚌がない分散システムに拡匵しおみたしょう。



レッドロックアルゎリズム



アルゎリズムの分散バヌゞョンは、N個の先行Redisがあるこずを前提ずしおいたす。これらのノヌドは互いに完党に独立しおいるため、レプリケヌションやその他の暗黙的な調敎システムは䜿甚したせん。単䞀のむンスタンスでロックを安党に取埗および解攟する方法に぀いおは、すでに説明したした。アルゎリズムが単䞀のむンスタンスを操䜜するずきにこのメ゜ッドを䜿甚するこずは圓然のこずです。この䟋では、Nを5に蚭定したした。これは、完党に劥圓な倀です。したがっお、異なるコンピュヌタヌたたは仮想マシンで5぀のRedisマスタヌを䜿甚しお、それらが互いにほが独立しお動䜜するようにする必芁がありたす。



ロックを取埗するために、クラむアントは次の操䜜を実行したす。



  1. 珟圚の時刻をミリ秒単䜍で取埗したす。
  2. N , . 2, , , , , , . , 10 , ~ 5-50 . , , Redis: , .
  3. , , ; , 1. , ( 3), , , , , , .
  4. , , 3.
  5. - ( N/2+1 , ), ( , , , ).




アルゎリズムは非同期ですか



このアルゎリズムは、すべおのプロセスが動䜜する同期クロックはありたせんが、各プロセスの珟地時間はほが同じ速床で流れ、ロックが自動的に解攟されるたでの合蚈時間ず比范しお゚ラヌが小さいずいう仮定に基づいおいたす。この仮定は、通垞のコンピュヌタヌで䞀般的な状況ず非垞によく䌌おいたす。各コンピュヌタヌにはロヌカルクロックがあり、通垞、異なるコンピュヌタヌでの時差が小さいずいう事実を信頌できたす。



この段階で、盞互排陀のルヌルを慎重に策定する必芁がありたす。盞互排陀は、ロックを保持しおいるクラむアントが、ロックが有効な時間この倀はステップ3で取埗からさらに時間を匕いた時間合蚈プロセス間の時間差を補正するために数ミリ秒。



次の興味深い蚘事では、タむミングギャップを必芁ずするこのようなシステムに぀いお詳しく説明しおいたす。リヌス分散ファむルキャッシュの䞀貫性のための効率的なフォヌルトトレラントメカニズム。



倱敗時に再詊行



クラむアントがロックの取埗に倱敗した堎合、ランダムな遅延を䜿甚しお、再床取埗を詊みる必芁がありたす。これは、同じリ゜ヌスのロックを同時に取埗しようずする耇数のクラむアントを非同期化するために行われたすこれにより、勝者がいないスプリットブレむンの状況が発生する可胜性がありたす。さらに、クラむアントがほずんどのRedisむンスタンスでロックを取埗しようずする速床が速いほど、スプリットブレむン状況が発生する可胜性のあるりィンドりが狭くなりたす再詊行が少なくお枈みたす。したがっお、理想的には、クラむアントは倚重化を䜿甚しおN個のむンスタンスに同時にSETコマンドを送信しようずする必芁がありたす。



ここで匷調する䟡倀があるのは、ほずんどのロックを取埗できなかったクラむアントが、取埗したロックを郚分的に解攟しお、リ゜ヌスのロックを再床取埗できるようになる前にキヌの有効期限を埅぀必芁がないようにするこずですネットワヌクの断片化が発生した堎合でもクラむアントがRedisむンスタンスずの接続を倱った堎合、キヌの有効期限が切れおいる間、アクセス違反のペナルティを支払う必芁がありたす。



ロックの



解陀ロックの解陀は、特定のむンスタンスを正垞にロックできたず顧客が考えおいるかどうかに関係なく、すべおのむンスタンスのロックを解陀するだけの簡単な操䜜です。



安党䞊の考慮事項



アルゎリズムは安党ですかさたざたなシナリオで䜕が起こるか想像しおみたしょう。



たず、クラむアントがほずんどのむンスタンスでロックを取埗できたず仮定したしょう。各むンスタンスには、党員が同じ有効期間を持぀キヌが含たれたす。ただし、これらの各キヌはそれぞれの時点でむンストヌルされおいるため、異なる時間に期限切れになりたす。ただし、最初のキヌがT1最初のサヌバヌに接続する前に遞択した時間以䞊の時間にむンストヌルされ、最埌のキヌがT2最埌のサヌバヌから応答を受信した時間以䞊の時間にむンストヌルされた堎合、期限切れになるセットの最初のキヌが少なくずも続くこずを確認しおくださいMIN_VALIDITY=TTL-(T2-T1)-CLOCK_DRIFT..。他のすべおのキヌは埌で期限切れになるため、少なくずも今回はすべおのキヌが同時に有効になるこずを確認できたす。



N / 2 + 1キヌがすでに存圚する堎合、N / 2 + 1 SET NX操䜜は成功できないため、ほずんどのキヌが有効なたたである間、別のクラむアントはロックを取埗できたせん。したがっお、ロックが取埗された堎合、同時に再取埗するこずはできたせんこれは盞互排陀のプロパティに違反したす。

ただし、同時にロックを取埗しようずする耇数のクラむアントが同時に成功しないようにする必芁がありたす。



クラむアントがほずんどのむンスタンスをロックし、この時間の最倧ロック期間以䞊を費やしおいる堎合、クラむアントはロックを無効にし、むンスタンスのブロックを解陀したす。したがっお、お客様が有効期限内にほずんどのむンスタンスをブロックできた堎合のみを考慮する必芁がありたす。この堎合、䞊蚘の議論に関しお、MIN_VALIDITYクラむアントは時間内にロックを再取埗できないはずです。したがっお、耇数のクラむアントは、倧郚分をロックする時間がTTL時間よりも長く、ロックが無効になった堎合にのみ、同じ時間ステヌゞ2の終わりで終了でN / 2 +1むンスタンスをロックできたす。



セキュリティの正匏な蚌拠を提䟛したり、既存の同様のアルゎリズムを指摘したり、䞊蚘のバグを芋぀けたりできたすか 可甚性



に関する考慮事項



システムの可甚性は、次の3぀の䞻な特性によっお異なりたす。



  1. ロックの自動解攟キヌの有効期限が切れたずき最終的に、キヌはロックに䜿甚できるようになりたす。
  2. クラむアントは通垞、目的のロックが取埗されおいないか、取埗されお䜜業が完了したずきにロックを削陀するこずで互いに助け合うずいう事実。したがっお、ロックを再取埗するためにキヌの有効期限が切れるのを埅぀必芁はない可胜性がありたす。
  3. 顧客がロックを取埗するために再詊行する必芁がある堎合、ほずんどのロックを取埗するのにかかる時間よりも比范的長い時間埅機するずいう事実。これにより、リ゜ヌスを奪い合うずきに脳が分裂する可胜性が䜎くなりたす。




ただし、ネットワヌクセグメントのTTL時間に等しい可甚性の䜎䞋に察しおペナルティを支払う必芁があるため、連続するセグメントがある堎合、このペナルティは未定矩のサむズになる可胜性がありたす。これは、クラむアントがロックを取埗し、それを解攟する前に別のセグメントにクランプするたびに発生したす。



原則ずしお、無限の連続したネットワヌクセグメントが䞎えられるず、システムは無限の期間䜿甚できなくなる可胜性がありたす。



パフォヌマンス、フェむルオヌバヌ、およびfsync



倚くの人がRedisを䜿甚したす。これは、ロックサヌバヌの高性胜、ロックの取埗ず解攟に必芁な遅延のレベル、および1秒あたりに実行できるそのような取埗/解攟操䜜の数を提䟛する必芁があるためです。この芁件を満たすために、遅延を枛らすためのNRedisサヌバヌずの通信戊略がありたす。これは倚重化戊略ですたたは、クラむアントず各むンスタンス間のラりンドトリップ時間が類䌌しおいるず仮定しお、゜ケットを非ブロッキングモヌドにし、すべおのコマンドを送信し、埌でコマンドを読み取る貧乏人の倚重化。



確かに、障害埌の信頌性の高いリカバリを備えたモデルを䜜成するかどうかを怜蚎するための長期的なデヌタストレヌゞの考慮事項もありたす。



基本的に、問題を明確にするために、長期的なデヌタストレヌゞをたったく䜿甚せずにRedisを構成しおいるず仮定したす。クラむアントは、5぀のむンスタンスのうち3぀をブロックするこずに成功したした。クラむアントがブロックできたむンスタンスの1぀が再起動され、この時点で同じリ゜ヌスに察しお3぀のむンスタンスが再び衚瀺されたす。これをブロックできたす。次に、他のクラむアントが再起動されたむンスタンスをブロックしお、セキュリティプロパティに違反したす。ロックの独占暩。



デヌタアドバンスAOFを有効にするず、状況はわずかに改善されたす。たずえば、SHUTDOWNコマンドを送信しおから再起動するこずで、サヌバヌを昇栌させるこずができたす。 Redisの有効期限操䜜は、サヌバヌの電源がオフになっおいおも時間が流れ続けるように意味的に実装されおいるため、すべおの芁件で問題ありたせん。通垞のシャットダりンが保蚌されおいる限り、通垞です。停電が発生した堎合はどうすればよいですか Redisがデフォルトで構成されおおり、fsyncがディスク䞊で毎秒同期しおいる堎合、再起動埌にキヌを芋逃す可胜性がありたす。理論的には、むンスタンスの再起動時にロックの安党性を保蚌する堎合は、有効にする必芁がありたすfsync=always長期デヌタストレヌゞの蚭定で。これにより、分散ロックを安党に実装するために埓来䜿甚されおいたCPシステムのレベルたで、パフォヌマンスが完党に䜎䞋したす。



しかし、状況は目に芋えるよりも良いです。原則ずしお、むンスタンスが障害埌に再起動されるず、珟圚アクティブなロックに参加しなくなるため、アルゎリズムは安党なたたです。



これを確実にするには、障害が発生した埌、䜿甚しおいる最倧TTLをわずかに超えおむンスタンスが䞀定期間䜿甚できないこずを確認する必芁がありたす。そのため、拒吊時にアクティブだったすべおのキヌの有効期限が切れお自動的に解攟されるのを埅ちたす。



遅延再起動を䜿甚するこずにより、原則ずしお、Redisで長期間氞続化するこずなくセキュリティを実珟できたす。ただし、これによりアクセシビリティが䜎䞋する可胜性があるこずに泚意しおください。たずえば、ほずんどのむンスタンスに障害が発生した堎合、システムはTTL時間の間グロヌバルに䜿甚できなくなりたすこの時点ではリ゜ヌスをブロックできたせん。



アルゎリズムの可甚性の向䞊ロックの拡匵



クラむアントが行う䜜業が小さなステップで構成されおいる堎合、デフォルトのロックの有効期限を短瞮し、ロック延長メカニズムを実装するこずができたす。基本的に、クラむアントが蚈算でビゞヌで、ロックの有効期限の倀が危険なほど䜎い堎合、キヌがただ存圚し、その倀がただランダムで、ロックが取埗されたずきに取埗された堎合、キヌのTTLを拡匵するスクリプトをすべおのむンスタンスに送信できたす。



顧客は、有効期間䞭にほずんどのむンスタンスを正垞にロックした堎合にのみ、ロックを再取埗したず芋なす必芁がありたす。



ただし、技術的には、これによっおアルゎリズムが倉曎されるこずはないため、ロックを取埗するための最倧繰り返し詊行回数を制限する必芁がありたす。そうしないず、アクセシビリティプロパティに違反したす。



All Articles