Redis を使用して分散ロックを実装する方法

PHPz
リリース: 2024-08-31 18:31:04
オリジナル
749 人が閲覧しました

私は愚かです

そうですね、ローカル システムで作業するときは常に、すべてがバターのように機能します。それが、私たちが 「127.0.0.1 に勝る場所はない」 と呼ぶ理由ですが、現実に目覚めてください

How to implement a Distributed Lock using Redis

まあ、本番環境では必ずしも期待どおりに動作するとは限りません。主に、アプリケーションの複数のインスタンスを実行している場合です。

How to implement a Distributed Lock using Redis

?ご覧のとおり、アプリケーションの複数のインスタンスが実行されており、クライアントが DB 内でユーザーを有料ユーザーとしてマークするリクエストを行ったとします。

  • クライアントはサーバーをリクエストします
  • リクエストはロードバランサーに到達します
  • インスタンスの 1 つがリクエストを取得し、DB に書き込みクエリを作成します

大丈夫そうですよね?今のところ問題ありません。

そうですね、今のところは問題ありません。しかし、次のようなビジネス ロジックを書きたい場合はどうなるでしょうか:-

  • DB からユーザーを取得します
  • ユーザーが無料ユーザーであるか、すでに有料ユーザーであるかを確認します
  • 無料の場合は、有料としてマークし、データベースに保存します
  • 支払われた場合は、応答で「支払い済み」を送信します。

⚡️ ご存知のとおり (ここでは MySQL を使用していると仮定します)、MySQL DB は ACID に準拠しており、これはすべてのクエリがアトミックで分離されることを意味します。これは、MySQL クエリがアトミックな方法で実行され、成功するか失敗するかを意味します。ただし、途中で終了することはありません。

?しかし、ここで問題が 1 つあります。考えて、考えて....

  • ステップ 1: ユーザーを取得しています (アトミック トランザクション)
  • ステップ 2: コードでビジネス ロジックを実行する
  • ステップ 3: ユーザーが支払いを行っていない場合に MySQL レコードを更新する (アトミック トランザクション)

ステップ 2 で支払いをキャンセルするリクエストがもう 1 つあり、そのクエリが最初に実行されてユーザーが無料としてマークされ、次にステップ 3 が実行されてユーザーが有料としてマークされた場合はどうなりますか。

??万歳、ユーザーは料金を支払うことなく当社の製品にアクセスできるようになりました。

ロック

✅ 救世主、ロックスの登場
How to implement a Distributed Lock using Redis

?ロックは、一度に 1 つのスレッドのみがクリティカル セクション (複数のワーカー、つまりスレッドによってアクセスされるべきではないコードのブロック) に入ることができる構造です

したがって、操作の完了前にロックを取得し、完了後に解放します。-

  • ステップ 0: try-acquire() ロック
  • ステップ 1: 取得した場合は、ユーザーを取得します (アトミック トランザクション)
  • ステップ 2: コードでビジネス ロジックを実行する
  • ステップ 3: ユーザーが支払いを行っていない場合に MySQL レコードを更新する (アトミック トランザクション)
  • ステップ 4: ロックを解放()します

?問題

ここで問題が発生します。それは、メモリ ロック データ構造またはメモリ ベースのロックを使用する場合、それがアプリケーションの 1 つのインスタンスに適格になるということです。同じコードを実行し、DB 内で更新している他のインスタンスはどうなりますか?

分散ロックの概念が登場します

?分散ロック

How to implement a Distributed Lock using Redis

ここでのロックは集中サービスとして機能し、サービスの 1 つのインスタンスがロックを取得すると、他のインスタンスは同じキーを使用できなくなります。

支払いサービスではどのようなキーがここにある可能性がありますか?

?ユーザーが支払いを行う場合、キーは = "PAYMENT_" + user_id + amount

の組み合わせになります。

これはユーザーごとに一意になります。そして、このキーは、ユーザーが支払いを行ったり、支払いをキャンセルしたりしても同じままになります。したがって、どちらかのアクションが同じキーを取得しようとするため、一方のアクションが発生しているときは、他のアクションを続行できません。

?一体何だ キー、ロックの取得、ロックの解除。そして最も重要なのは、Redis がどのように使用されているのかということです。


? Redis を使用して分散ロックを実装する

Redis の単一インスタンスの使用:-

How to implement a Distributed Lock using Redis

しかし、単一の Redis インスタンスにはいくつかの問題があります:-

  • 単一のインスタンスが失敗し、取得したロックが解放されない可能性があります
  • 1 つのクライアントが 1 つのインスタンスのロックを取得するときに 2 つのインスタンスが使用される場合 (マスター-レプリカ)
  • マスターは同期するためにレプリカと同様に通信する必要があります。この通信自体は非同期通信です

?つまり、マスターでロックが取得され、レプリカとの通信中にマスターがレプリカと同期する前にダウンした場合です。レプリカはマスターになり、以前にマスターで取得したものと同じキーのロックを取得できるようになります。

サービスの 2 つのインスタンスは、2 つのインスタンス (マスター レプリカ) がある場合でも、Redis 上のロックを取得できます。

Redlock アルゴリズムの使用:-

ロックの取得:- ロックの有効期限を指定して複数の Redis インスタンスのロックを取得しようとします
ロックの検証:- 主要な Redis インスタンスがクライアントに対してロックを取得した場合、ロックは取得されたものとみなされます
ロックの解放:- ロックを解放すると、すべてのインスタンスがロックを解放します

How to implement a Distributed Lock using Redis

はい、それだけです。

❤️ お読みいただきありがとうございます。このような記事をさらにご覧いただくためにニュースレターを購読してください:- https://www.serversidedigest.com/

詳細情報:-

  • Java の Jedis:- https://redis.io/docs/latest/develop/connect/clients/java/jedis/
  • Golang の Redis クライアント:- https://github.com/redis/go-redis

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

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート