ホームページ  >  記事  >  データベース  >  Redis を使用してリソースをロックする方法

Redis を使用してリソースをロックする方法

WBOY
WBOY転載
2023-05-28 11:01:45933ブラウズ

1. 概要

このテクノロジーは更新され、反復され続けるため、企業内では分散の概念がますます重視されるようになってきています。分散について話すとき、必ず分散ロックの話が出てきますが、現時点で分散ロックの実装方法としては ZookeeperDB Redis、の 3 つが主流です。この記事では例として Redis を使用します。

私たちの観点からすると、これら 3 つのプロパティは、分散ロックを効果的に使用するために必要な最低限の保証です。

  1. 安全機能: 相互に排他的です。常に 1 つのクライアントだけがロックを保持できます。

  2. 活力属性: デッドロックなし。最終的には、リソースをロックしているクライアントがクラッシュしたり分割された場合でも、ロックは常に取得できます。

  3. アクティビティ: フォールト トレランス。 Redis ノードの大部分が実行されている限り、クライアントはロックを取得および解放できます。

2. 分散ロックの Redis マルチノード実装によってもたらされる課題

Redis を使用してリソースをロックする最も簡単な方法は次のとおりです:

  1. インスタンスにロックを作成します。

  2. ロックは通常、Redis の有効期限機能を使用して限られた期間のみ存在するため、最終的には解放され、特定の期間が経過すると最終的には削除されます。

  3. クライアントはリソースを解放する必要がある場合、ロックを削除します。

一見すると問題ないようです。しかし、詳しく見てみると、この実装スキームは Redis スタンドアロン環境では問題ないようです。しかし、ノードがダウンしたらどうなるでしょうか?さて、slave ノードを追加しましょう。メインサーバーがダウンした場合は、このノードを使用してください。しかし、彼女が本当に対応できることが保証されているかどうかを見てみましょう?

この致命的な欠陥について話すときは、Redis レプリケーションが非同期であるという 1 つの知識ポイントを理解する必要があります。

  1. クライアント A がメイン サーバーのロックを取得します。

  2. マスターはロックのコピーをスレーブに転送する前にクラッシュしました。

  3. スレーブに昇格 マスター

  4. スレーブにはロックのオブジェクトがないため、クライアント B がロックを取得し、取得は成功しました。

これは明らかに間違っています。データを同期する前にマスター ノードがダウンしたため、スレーブ ノードにはデータがなく、分散ロックが失敗します。著者antirez の視点は、これをどう解決するかということです。

3. Redlock アルゴリズム

著者は、複数の Redis を使用する必要があると考えています。これらのノードは完全に独立しており、レプリケーションや調整のためのシステムを使用する必要はありません。複数の Redis システムのロックを取得するプロセスは次の手順になります:

  1. 現在のサーバー時刻をミリ秒単位で取得します

  2. 使用してみるロックを取得するには、同じキーとランダムな値を使用します。ロックを取得するときは、各マシンにタイムアウトが必要です。たとえば、ロックの有効期限が 10 秒の場合、単一ノード ロックを取得するためのタイムアウトは約 5 秒である必要があります。 50 ミリ秒。彼はこんな感じです。目的は、クライアントが障害が発生したマシンに確実に接続されるようにすることですが、これにより余分な時間が無駄になります。タイムアウト期間内にデータが取得されない場合、ノードは破棄され、すべてのノードが取得されるまで次のノードが取得されます。

  3. 取得が完了したら、現在の時刻から手順 1 で取得した時刻を引いた時刻を取得します。クライアントの半数以上が正常に取得し、ロックの取得時間が短縮された場合に限ります。ロック量のタイムアウト未満であれば、ロックが有効であることが証明されます。

  4. ロックを取得した後のロック タイムアウトは次のとおりです。 設定された有効時間 - ロックを取得するのにかかる時間

  5. #ロックを取得したマシンの半数以上が満足していない場合、またはロックが計算などの操作後にタイムアウトが負の場合、システムはすべてのインスタンスのロックを解除しようとします。一部のインスタンスがロックの取得に失敗した場合でも、ロックの解除が試行されます。

  6. ロックを解放します。クライアントが指定されたインスタンスを正常にロックできると考えるかどうかに関係なく、すべてのインスタンスのロックを解放します。

4. しかし、Redlock は本当に問題を解決できるのでしょうか?

Martin Kleppmann が記事タスク「Redlock はロックの安全性を保証できない!」を公開しました。

彼は、ロックの使用方法は 2 つだけだと考えています。

  1. 効率を向上させるには、ロックを使用して、タスクを 2 回実行する必要がないようにします。たとえば、(非常に高価な計算)

  2. 精度を確保するために、ロック メカニズムを使用して、タスクが通常のプロセス順序で実行されるようにし、2 つのノードが同じデータで動作するのを回避します。同時に、ファイルの競合とデータの損失が発生します。

第一の理由は、ロックに対して一定の許容度を持っているため、2 つのノードが同時に動作したとしても、システムへの影響は余分な労力だけです。計算コストがかからず、追加の影響はありません。現時点では、単一ポイントの Redis を使用することで問題をうまく解決でき、非常に多くの Redis インスタンスを保守してシステムの保守コストを増加させるために RedLock を使用する必要はありません。

1. 分散ロックのタイムアウトによって引き起こされる欠点

ただし、2 番目のシナリオでは、金銭的な取引が含まれる可能性が高いため、より慎重になる必要があります。ロックが失敗した場合、および 2 つのノードの場合は、同じデータを同時に処理すると、ファイルの破損、データの損失、永続的な不整合、または金銭的損失が発生します。

2 つのクライアントがあるシナリオを想定します。各クライアントは、データをデータベースに保存する前にロックを取得する必要があります。RedLock アルゴリズムを使用して実装すると、どのような問題が発生しますか? RedLock では、デッドロックを防ぐために、ロックに有効期限が設定されていますが、Martin は、これは安全ではないと考えています。フローチャートはこんな感じです!

Redis を使用してリソースをロックする方法

クライアント 1 がロックの取得に成功した後、実行を開始しましたが、実行の途中でシステム内でフル GC が発生し、システム サービスが一時停止され、しばらくしてロックがタイムアウトしました。

クライアント 2 は、クライアント 1 のロックがタイムアウトするのを待った後、ロックを正常に取得し、ウェアハウジング操作の実行を開始しました。完了後、クライアント 1 はフル GC を完了し、別のウェアハウジング操作を実行しました。これは危険です!どうやって解決すればいいでしょうか?

Martin は、オプティミスティック ロックに似た実装メカニズムを提案しました。図の例は次のとおりです。

クライアント 1 が長期間中断された後、クライアント 2 はロックを取得し、トークン Redis を使用してリソースをロックする方法34
を運ぶライブラリの書き込みを開始しました。ライブラリの書き込み後、クライアント 1 は起動しました。操作が開始されましたが、保持されているトークンが 33 であり、最新のトークンより小さいため、送信は拒否されました。

システムにハングを引き起こす問題が発生した場合でも、データが正しく処理されることを保証するこのアイデアは完成したように見えます。しかし、考えてみてください:

データストアは、トークンが過去のすべてのトークンよりも大きい場合にのみ書き込みを常に受け​​入れることができる場合、線形化可能なストアです。これは、データベースを使用してデータ ストアを実装するのと同じです。分散ロックシステムを導入すると、RedLock の役割は最小限になります。分散ロックを保証するために Redis を使用する必要さえありません。
  • 2.RedLock はシステム クロックに強く依存します
ロックを取得するための

Redlock アルゴリズム

の手順を思い出してください。有効性がわかります。ロックの現在のシステム クロックに大きく依存します。次のことを想定します:

A B C D E 5 つの Redis ノードがあるとします:

クライアント 1 はノード A、B を取得します、Cロック。ネットワークの問題により、D と E にアクセスできません。
  1. ノード C のクロックが進み、ロックが期限切れになります。
  2. クライアント 2 は、ノード C、D、および E のロックを取得します。ネットワークの問題により、A と B にアクセスできません。
  3. さて、クライアント 1 と 2 はどちらもロックを保持していると考えています。
  4. C がクラッシュし、ディスクへのロックを永続化する直前に再起動した場合にも、同様の問題が発生する可能性があります。
Martin は、システムの時間ステップは主に 2 つの側面 (および著者が提供する解決策) から来ると考えています:

人間の改造。
  1. 人間の改造について何が言えますか?人間が破壊を引き起こすのを防ぐ方法はありません。
  • ジャンプタイム クロックの更新を NTP サービスから受信しました。
  • 運用および保守担当者は、ステップ クロックの更新を受け入れる NTP の問題に対処する必要があります。ステップ時間をサーバーに更新する必要がある場合は、小さなステップを実行して迅速に実行する必要があります。複数回変更し、各更新にかかる時間をできるだけ短くする必要があります。
    • 3. 分散ロックのタイムアウトによって引き起こされる欠点を補うためのプログラミング言語に基づく
    1 つの観点を確認し、この抽象化欠陥の根本原因 システムダウンによるロックの失敗と、ロックに有効期限を課すことで引き起こされる一連の問題を解決するためであり、異常時においてはプログラム(業務)の実行時間が通常の実行時間よりも長くなる。ロックの有効期限。ここから始めてもいいでしょうか? この点を考慮して、このようなデッド状況を解決するプログラムを使用する必要がありますか?

    業務プログラムの実行時間がロックタイムアウトよりも絶対的に短いことが保証できるため、ロックの有効期限が業務時間よりも短いという問題を回避できます。 Java 言語では、

    redisson

    は、ロックの有効期限がビジネス プログラムの実行時間よりも絶対に長くなることを保証する A メカニズムを実装します。正式にはウォッチドッグ メカニズム (Watchdog) と呼ばれ、その主な原理は、プログラムがロックの取得に成功した後、子スレッドをフォークして、ロックが解放されるまで継続的にロックを更新することです。彼の概略図は次のようになります:

    redisson はデーモン スレッドを使用してロックを更新します (デーモン スレッドの役割:

    メイン スレッド
    が破棄されると、Redis を使用してリソースをロックする方法メイン スレッド
    と一緒に破棄されます)。プログラム ダウンタイム後もスレッドは存続し、デッドロックが発生します。

    さらに、Redisson は RedLock アルゴリズム、フェア ロック、リエントラント ロック、チェーン、その他の操作も実装および最適化しているため、Redis 分散ロックの実装がより簡単かつ効率的になります。

    以上がRedis を使用してリソースをロックする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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