ホームページ  >  記事  >  データベース  >  Redis は分散ロックをどのように実装しますか?導入方法について話しましょう

Redis は分散ロックをどのように実装しますか?導入方法について話しましょう

青灯夜游
青灯夜游転載
2021-11-30 19:25:071876ブラウズ

Redis を使用して分散ロックを実装するにはどうすればよいですか?以下の記事ではRedisをベースに分散ロックを実装する方法を紹介しますので、ご参考になれば幸いです。

Redis は分散ロックをどのように実装しますか?導入方法について話しましょう

#分散システムでは、複数のノードで共有されるリソースをロックする必要がある場合があり、この場合は分散ロックを使用する必要があります。分散ロックは通常、共有ストレージ システムに保存され、複数のノードで共有してアクセスできます。 [関連する推奨事項: Redis ビデオ チュートリアル ]

ロックの本質

簡単に言えば、ロックは変数で表すことができます。たとえば、単一マシンのマルチスレッド プログラムでは、特定のリソースのロックを 1 ビットのデータで表すことができます。つまり、0 はリソースにアクセスできないことを意味し、1 はリソース ロックが別のスレッドによって取得され、アクセスできないことを意味します。

特定のリソースのロックの取得と解放は、基本的にこの変数の値を取得して変更することです。値が 0 の場合は、1 に変更して取得プロセスを完了します。アクセスされた値が 0 でない場合、ロックの取得は失敗します。ロックが以前に取得されている場合は、ロックを表す変数の値が次のように変更されます。 0. 実はロックを解除する操作です。

分散シナリオでは、リソース ロックを表す変数を共有ストレージ システムに保存する必要があることを除いて、ロックを実装する方法は同じです。この共有ストレージ システムには、Redis またはデータ ストレージを提供できるその他のシステムを使用できます。

Redis による分散ロックの実装

ステップ 1: 機能の予備実装

この共有ストレージ システムとして Redis を使用する場合、特定のリソースのロックを表す変数は、Redis のキーと値のペアです。分散ロックを追加する必要があるリソースが resource_a と呼ばれる場合、Redis lock_a で resource_a のロック変数のキーを呼び出すことができます。

たとえば、ノード 1 がロックを取得する必要がある場合、ノード 1 は Redis の lock_a の値にアクセスし、取得した値が 0 であると仮定すると、ノード 1 はこの値を 1 に設定してロック操作を完了します。このとき、ノード 2 も resource_a のロックを取得する必要があります。Redis の lock_a の値にアクセスすると、その値が 1 であることがわかり、ロックは別のノードによって取得されており解放されていないことがわかります。 2 つはリソース resource_a のロックに失敗します。

ノード 1 がロックを解放する必要がある場合、Redis の lock_a の値を 0 に設定するだけでロックの解放が完了し、その後、他のノードが再度リソース ロックを取得できるようになります。

ステップ 2: ロック操作を原子化する

上記の説明では、ロックは 1 つの操作ではなく、複数のステップが含まれています。ロック変数を読み取り、値を決定します。変数の値を変更し、ロック変数を変更します。これら 3 つの操作はアトミックである必要があります。

Redis には、キーと値のペアの値を設定するための SETNX コマンドがあり、SET コマンドとは異なり、キーと値のペアが事前に存在するかどうかを判断し、指定したKEYが存在しない場合 値が設定されている場合のみ値の設定が実行され、それ以外の場合は何も実行されません。 SETNX は、「SET if Not e#XXist」を意味します。使用方法は SET と同じです:

SETNX lock_a 1

このように、ロックを取得する必要がある場合は、SETNX コマンドを使用して lock_a の値を設定します。設定が成功すると、ロックが取得されます。失敗すると、ロックは取得されません。必要に応じてロックを解放するときは、DEL 操作を使用してキーと値のペアを削除します。

これにより、ロックの取得と解放というアトミックな操作が実現されます。

第 3 ステップ: ロック後にロックが解放されないことを防ぐ

次に、ノードがロックを取得した後、プログラム例外が原因で問題が発生した場合は、早期に問題を検討します。ロックが解除されていないなどの理由により、ロックが常に保持されたまま解除できず、他のノードはリソースにアクセスできなくなります。

この状況が起こらないようにするには、ロック変数の有効期限を設定する必要があります。ロック変数の有効期限が切れたら、ロックを再要求できるため、この問題は回避できます。

SETNX コマンドには有効期限を設定するオプションがありません。幸いなことに、Redis には SET コマンドの SETNX をシミュレートする NX オプションが用意されています。有効期限は次のように設定できます:

SET lock_a 1 NX PX 10000

上記のコマンドは を表します。lock_a が存在しない場合、その値は 1 に設定され、10 秒後に期限切れになります。

ステップ 4: 誰がロックし、誰が解放するのか

#最後の質問は、ノード 1 がロックを取得し、何らかの理由でノード 2 が DEL 操作を実行した場合です。他のノードは再びロックを取得できます。

この問題を解決するには、ロック変数に保存されている内容を変更します。前のロジックでは、ロックを申請するときにロック変数が存在するかどうかを判断しますが、これはそこに格納されている値とはほとんど関係がないため、この値を使用できます。

ロックする際、値を各ノードの一意の識別子として保存しておけば、ロックを解除してDELを実行する前に値を判定することで、まず現在のノードにロックが追加されているかどうかを判定できます。はい、その後、それを解放します。これにより、「ロックをロックした人がロックを解放する」ことが実現します。

この部分は、ロック変数の読み込み、判定、削除までを単一の命令で完結できるものではないため、Luaスクリプトで実装することが可能です。スクリプト内の現在のロック変数の値を取得し、指定されたノード識別子と比較します。一致する場合は削除操作が実行され、そうでない場合は操作は実行されません。

ロックを解除するときは、Lua スクリプトを実行するだけです。

ステップ 5: 高可用性の実装

機能を改善したら、最後に高可用性を実装します。単一の Redis を分散ロックの共有ストレージ システムとして使用する場合、この Redis が利用できなくなると、分散ロックに関連するすべての部分が利用できなくなります。これにより、ロックが非常に脆弱になり、高可用性を実現するために非常に役立ちます。必要な理由があります。

この時点で、Redis の作者である Antirez が提案した分散ロック アルゴリズム Redlock を移行する必要があります。つまり、ロック申請者は複数の独立した Redis インスタンスにロックを要求するように求められ、半数以上の Redis インスタンスでロック操作が完了できればロックの取得に成功し、そうでない場合は取得に失敗します。

ロックの解放操作は、ロック変数の削除に成功したLuaスクリプトが半数以上のインスタンスで実行されていれば成功とみなします。

プログラミング関連の知識について詳しくは、プログラミング入門をご覧ください。 !

以上がRedis は分散ロックをどのように実装しますか?導入方法について話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。