この記事では、Redis のロックについて説明し、ロックが使用される理由を紹介します。Redlock (Redis 分散ロック) は本当に必要ですか? 皆様のお役に立てれば幸いです。
ロックを使用する理由
私が働いていた幼稚園から高校までの教育会社では、次のようなビジネスがありました。シナリオはこんな感じ。企業側は学生の授業を手配する必要があるため、明らかに授業時間は足りているのに授業時間が足りない、ページを更新すると授業時間が足りていないことが判明するという声が時々寄せられます。さらに恐ろしいのは、場合によっては学生の授業時間がマイナスに差し引かれることです(会社の授業時間が無料で使われることになります)。 [関連する推奨事項: Redis ビデオ チュートリアル ]
別の例は次の例です
上記の 2 つの質問は、発生した問題に対して送信されます。私たちのビジネスから。この問題に対する中心的な解決策は、これらの機密 (重要) データの読み取りと書き込みを同時に許可できるリクエストは 1 つだけであるということです。したがって、現時点では分散ロックを使用してプログラムの同時実行を制限する必要があります。
setnx の問題点は何ですか
まず、誰もがよく知っている Redis を使用して分散ロックを実装する方法を見てみましょう。 。たとえば、記事の冒頭で述べた学生クラスのスケジュールの問題については、次のようにロックできます。
これは、setnx を日常的に使用してロックを実装する方法です。
ここで、そのようなシナリオがあると仮定します。 A にロックの取得を要求すると、学生のクラスをスケジュールするときにプログラムがステップ 2 でハングアップし、ロックが解放されませんでした。その後、ロックはデッドロックになり、同じ学生を操作する次のリクエストはロックを取得できず、学生をスケジュールすることはできません。このとき、手動でロックを解除する必要があります。
デッドロックの問題を解決するために、ロックに有効期限を追加します。
有効期限を追加した後、リクエスト A がロックをアクティブに解放しない場合、ロックの有効期限が切れた後にロックがアクティブに解放されるため、リクエスト B もロックを取得できるようになります。ビジネスロジックを処理します。ただし、有効期限を追加すると、ステップ 1 と 2 の間でプログラムがクラッシュします。その場合、依然としてデッドロックの問題が発生します。この問題の根本は、setnx と Expire の 2 つの命令がアトミック命令ではないことです。したがって、setnx と Expire がそれらをすべて実行するか、まったく実行できないかのいずれかにできれば便利です。
このため、この問題を解決するために、Redis2.8 が登場する前にコミュニティで多数の拡張パッケージが登場しました。この混乱を制御するために、公式はバージョン 2.8 で set 命令の拡張パラメータを追加し、setnx 命令と Expire 命令を一緒に実行できるようにしました。そのため、今後はこのような分散ロックを使用する必要があります
これは完璧に見えます。「setnx と Expir がそれらをすべて実行するか、まったく実行しないことができれば素晴らしいでしょう」という私たちの期待を達成しました。次のシナリオがあると仮定します。
リクエストがロックを取得し、ロックのタイムアウトが 5 秒に設定されています。手順2ではビジネスロジックが実行されますが、何らかの理由で5秒経過してもビジネスロジックが完了せず、タイムアウトによりロックが自動的に解除されます。このときリクエストBも来ており、ロックを取得した後、ビジネスロジックの実行が開始されました。この時点で、A のリクエストのビジネス ロジックが実行され、3 番目のステップが開始され、ロックが解除されます。このとき、B の要求によりロックが取得されましたが、A の要求によりロックが解除されました。その後、C リクエストはロックを取得できます。このとき、リクエスト B とリクエスト C では同時実行の問題が発生します。したがって、この例からわかるように、分散ロックの有効期限の設定は非常に重要であり、設定時間がこのインターフェイスの応答時間よりも短い場合でも、同時実行の問題が発生します。したがって、インターフェイスの応答時間の監視を参照して、ロックの有効期限を設定できます。
Redlock
上記のソリューションはすべて、シングルポイント Redis 実装に基づいています。分散ロックのシングルポイント Redis 実装は、基本的にビジネス シナリオの 95% を満たすことができます。残りの 5% は、データの整合性とロック損失に対するゼロトレランスに関する非常に厳しい要件を伴うビジネス シナリオです。現時点では、Redlock を考慮する必要があります。シングルポイントRedisの場合、sentinelによる高可用性を確保していても、何らかの理由でマスターノードがマスター/スレーブを切り替え、マスターとスレーブのデータ同期が間に合わないとデータ損失やロック損失が発生します。 。
複数の Redis インスタンスがあると仮定します。これらのノードは完全に独立しており、データを調整するためにレプリケーションやシステムを使用する必要はありません。5 つの Redis マスター ノードがあると仮定します。クライアントがロックの場合、手順は次のようになります:
現在のサーバー時刻をミリ秒単位で取得します
同じキーとランダムな値を使用してロックを取得してみます。クライアントは、各マシンでロックを取得するときにタイムアウト期間を設ける必要があります。たとえば、ロックの有効期限が 10 秒の場合、単一ノードのロックを取得します。タイムアウト時間は約 5 ~ 50 ミリ秒にする必要があります。この目的は、クライアントが障害が発生したマシンへの接続に余分な時間を費やさないようにすることです。タイムアウト期間内にデータが取得されない場合、ノードは破棄され、次の Redis ノードが取得されます。
取得が完了したら、クライアントが半分以上 (ここでは 3 ノード) からロックを取得した場合に限り、現在の時刻からステップ 1 で取得した時刻を引いた時刻を取得します。 Redis ノードとロックを取得する時間がロック タイムアウトよりも短い場合は、ロックが有効であることが証明されます。
ロックが取得された場合、キーの実際の有効時間は、有効時間からロックの取得に使用された時間を引いたものになります (手順 3 で計算された結果)。
ロックを取得したマシンの半数以上が満たされていない場合、または計算後のロック タイムアウトが負の場合、またはその他の異常な操作がある場合、システムはすべてのインスタンスのロックを解除しようとします。一部の Redis インスタンスがまったくロックされていない場合でも、ロックが成功しない場合、一部のノードがロックを取得できなくなりますが、クライアントは応答を取得せず、一定期間ロックを再取得できません
これで、実際にレッドロックが確認できます。シングルポイント Redis よりも信頼性が高いと思われるロックです。
あなたが私のような Node.js プログラマーの場合は、直接使用できるサードパーティ ライブラリ redlock があります。
レッドロックは本当に必要ですか?
実は、レッドロックについては別の声もあります。Martin Kleppmann (ケンブリッジ大学の研究者、データベースに従事、分散システムと情報セキュリティが交わる TRVE DATA プロジェクトは、記事 blog を執筆し、レッドロックに関するいくつかの見解を表明しました。 Redis の作者 Salvatore も、この記事の質問に対していくつかの 回答 を行っていますが、これは非常に興味深いものです。著者のブログの要点は次のとおりです。
分散ロックの使用法は 2 つまでです。
効率性を重視するのであれば、Redlock のコストと複雑さを負担する必要はありません。ロックの損失によりさらに数回メールを送信するコストや、5 台の Redis サーバーを実行するコストと比較すると、単一の Redis サンプルのみを使用することをお勧めします。単一の Redis インスタンスを使用していて、Redis ノードが突然電源を失ったり、クラッシュしたり、その他の問題が発生した場合、当然、この時点でロックが失われます。ただし、効率の最適化としてロックを使用しているだけで、このクラッシュが頻繁に発生しない場合は、大した問題ではありません。この「大したことはない」シナリオは、まさに Redis が優れている点です。少なくとも、単一の Redis インスタンスに依存している場合は、システムを見ている全員が問題をより簡単に特定できるようになります。
厳密に言えば、redlock には強整合性の厳密性はまったくありません。いくつかの例を示します。
タイミングとシステム クロックは危険な仮定を立てており、各サーバーのクロックに大きく依存しています。システムには GC が存在するため、GC 中にサーバー全体が負荷をかけられ、時間が停滞するため、クロックに強く依存することはできません。
プログラミング入門をご覧ください。 !
以上がRedis のロックの簡単な分析、Redlock (Redis 分散ロック) について話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。