Zookeeperが分散ロックを実装する原理

Zookeeperが分散ロックを実装する原理

[[384001]]

この記事はWeChatの公開アカウント「Rookie Flying」から転載したもので、著者はLiu Jinkunです。この記事の転載については、Cainiao Feiyafei公式アカウントまでご連絡ください。

序文

ByteDance の面接を受けたとき、次のような質問に遭遇しました。「Zookeeper を使用して分散ロックを実装するにはどうすればよいですか?」

ほとんどの面接では、Redis を使用して分散ロックを実装することについて取り上げられており、Zookeeper を使用して分散ロックを実装することは比較的一般的ではないと思います。最近、過去のインタビューの回答を整理していたので、それを説明するブログを書きました。

通常、分散ロックを実装する方法は多数ありますが、より一般的なのは redis と Zookeeper です。皆さんは、Redis の分散ロックの実装についてはすでによくご存知だと思います。今日はZookeeperを使って分散ロックを実装する方法を紹介します。

まず、Zookeeper が分散ロックを実装できるのはなぜでしょうか?これは、複数のスレッドが Zookeeper にアクセスして同じノードを作成する場合、1 つのスレッドのみが正常に実行されるという機能があるためです。

動物園の飼育係 ZNode

Zookeeper が分散ロックを実装する方法を理解する前に、まず、Zookeeper のノードに関連する知識を理解する必要があります。

Zookeeper 内のノードは、一時ノードと永続ノードの 2 つのカテゴリに分けられます。

一時ノードとは、ノードが作成された後に、ノードを作成したクライアントと Zookeeper サーバー間のセッションが失敗した場合 (たとえば、接続が切断された場合)、ノードが削除されることを意味します。

永続ノードとは、ノードが作成された後に、ノードを作成したクライアントと Zookeeper サーバー間のセッションが失敗した場合でも (たとえば、接続が切断された場合)、ノードは削除されないことを意味します。ノードは、クライアントがノードの削除要求を積極的に開始した場合にのみ削除されます。

順序付きノードと呼ばれる別のタイプのノードもあります。このタイプのノードは、作成時にシリアル番号が付与され、このシリアル番号は自動的に増加します。順序付けられたノードは、順序付けられた一時ノードまたは順序付けられた永続ノードのいずれかになります。

Zookeeper 内のすべてのデータはノードを通じて保存され、そのディレクトリ構造は以下に示すようにファイル ツリーのようになります。

飼育員の構造

図のロック、レジスタ、およびデータ ディレクトリはカスタム作成され、さまざまなビジネスのデータを保存するために使用されます。たとえば、locks は分散ロックに関連する情報を格納するために使用され、register は登録センターに関連するデータを格納するために使用されます。

ここで、分散ロックを取得したいと思います。このロックの K を K1 と呼ぶことにします。ここでクライアント a が存在し、分散ロックを作成するために JK に移動します。分散ロック K1 を作成すると、nex ディレクトリの下に K1 というフォルダーと K1 というファイルが作成されます。ここで、分散ロックを取得したいと思います。このロックの K を K1 と呼ぶことにします。ここでクライアント a が存在し、分散ロックを作成するために JK に移動します。分散ロック K1 を作成すると、nex ディレクトリの下に K1 というフォルダーと K1 というファイルが作成されます。

達成方法

Zookeeper を使用して分散ロックを実装するには、次の 2 つのソリューションがあります。1. 一時ノードに基づく実装。 2. 一時的な順次ノードに基づく実装。このソリューションの実装原理を以下に紹介します。

まず、すべての分散ロックがロック ディレクトリに保存されていると仮定します。

解決策 1: 一時ノードに基づく (非推奨)

クライアント A、B、C がすべて同じ分散ロック Key1 を取得すると仮定します。

まず、クライアント A は分散ロック Key1 を取得し、次にロック ディレクトリに Key1 という ZNode ノードを作成しようとします。この時点でロック ディレクトリに ZNode Key1 がない場合、クライアント A は Key1 ノードを正常に作成できます。つまり、クライアント A は Key1 ロックを正常に取得できます。

図1

同時に、クライアント B もロック Key1 を取得するようになります。クライアント B は、ロック ディレクトリに Key1 ZNode ノードも作成する必要があります。この時点で、Key1 ZNode ノードがすでに存在するため、クライアント B はそれを作成できません。作成に失敗すると、クライアント B はロックを取得できないため、この時点でクライアント B は独自のリスナー (ウォッチャー) を Zookeeper に登録し、ZNode ノード Key1 の変更を監視します (Key1 ノードが変更されると、Zookeeper はクライアント B に通知します)。

クライアント A とクライアント B が同時に Zookeeper を要求した場合、Zookeeper には、クライアントの 1 つだけが ZNode ノード Key1 を正常に作成できるようにするメカニズムがあります。

図2

同様に、クライアント C が Key1 ロックを取得しようとしても、ロックを取得できません。また、Key1 ZNode ノードの変更を監視するために、ZK に独自の Watcher を登録します。

クライアント A は独自のビジネス ロジックの処理を完了すると、ロックを解除します。ロックを解除すると、クライアントは Key1 ノードを削除します。ノードが正常に削除された場合、ロックが正常に解除されたことを意味します。 Key1 ノードが削除されると、Zookeeper は Key1 ノードを監視するすべてのクライアント、つまりクライアント B と C に通知します。

クライアント B と C は通知を受信し、Key1 ノードが変更されたことを認識すると、再度 Zookeeper を要求し、locks ディレクトリの下に Key1 ノードを作成しようとします。現時点では、Key1 ノードを正常に作成できるクライアントは 1 つだけです。クライアント B が正常に作成された場合、クライアント B がロックを正常に取得したことを意味します。クライアント C がロックの取得に失敗した場合、Key1 ノードの変更を監視し続けます。

図3

推奨されない理由

上記は、Zookeeper 分散ロックを実装するための一時ノードに基づくソリューションですが、このソリューションは通常は推奨されません。なぜ?なぜなら、この解決策を使用すると群集効果という大きな問題が生じるからです。

それはどういう意味ですか?

上記のプロセスから、クライアント A がロックを正常に解放すると、Zookeeper は Key1 ノードをリッスンしているすべてのクライアントに通知する必要があることがわかります。上記の例ではクライアント B と C しかありませんが、実際のアプリケーションではクライアントの数は数百、数千、あるいはそれ以上になる場合があります。現時点で Zookeeper は数百または数千のリクエストを送信する必要があります。まず第一に、この効率は明らかに高くありません。さらに、分散ロックの競争が激しくなると、Zookeeper のネットワーク カードがこの時点で圧倒される可能性が高くなります。さらに、システムには Key1 だけでなく、Key2、Key3、Key4 などが存在する可能性があります。これらのロックも競合の対象となる可能性があり、Zookeeper にさらに負担がかかります。

このプロセスでは、分散ロックを取得するときにクライアントの 1 つしかロックを取得できないため、これが不合理であることがはっきりとわかります。したがって、Key1 ノードが削除された場合は、他のクライアントにロックを取得するように通知する必要があります。現時点ですべてのクライアントに通知する必要がありますか?

明らかにこれは必要ではなく、クライアントの 1 つに通知するだけで済みます。したがって、オプション 2 が出現しました。

ソリューション2: 一時的なシーケンシャルノードに基づく実装(推奨)

一時シーケンシャルノードに基づいて分散ロックを実装する場合、一時ノード Key1 は Linux ディレクトリの下に作成されません。代わりに、まず locks ディレクトリの下に Key1 ディレクトリを作成し、次に Key1 ディレクトリに一時シーケンス ノードを作成します。

クライアント A が分散ロック Key1 を取得したと仮定します。このとき、クライアント A は Key1 ディレクトリに一時シーケンス ノードを作成します。この一時シーケンス ノードのシーケンス番号は 001 です。

次に、クライアント A は、作成した一時シーケンス ノード 001 が Key1 ディレクトリ内で最小のシーケンス番号を持っているかどうかを判断します。最小の場合、クライアント A がロックを正常に取得したことを意味します。

次に、クライアント B も分散ロック Key1 を取得し、Key1 ディレクトリの下に一時シーケンス ノードも作成します。この時点で自動増分シーケンス番号は 002 になっており、以前に 001 が作成されているため、クライアント B は一時シーケンス ノード 002 を作成します。

図4

同様に、クライアント B は、作成した一時シーケンス ノード 002 が現在の Key1 ディレクトリ内で最小のシーケンス番号を持つ一時ノードであるかどうかも判断します。明らかにそうではありません。その前に一時シーケンス ノード 001 があるため、クライアント B はこの時点でロックを取得できません。

クライアント B がロックの取得に失敗すると、クライアント B は Zookeeper に独自のリスナーを登録し、そのリスナーは以前の一時シーケンス ノード、つまりシーケンス ノード 001 をリッスンします。

図5

このとき、クライアント C も分散ロック Key1 を取得する場合、Key ディレクトリに一時シーケンス ノード 003 を作成します。同様に、003 は最小のシーケンス番号を持つ一時シーケンス ノードではないため、クライアント C もロックを取得できず、一時シーケンス ノード 002 をリッスンすることになります。

クライアント A はビジネス ロジックの処理を完了すると、ロックを解除します。ロックを解除する操作は、クライアント A がディレクトリ Key1 の下に作成した一時シーケンス ノードを削除すること、つまり一時シーケンス ノード 001 を削除することです。シーケンス ノード 001 が削除されると、Zookeeper はシーケンス ノード 001 を監視するすべてのクライアントに通知します。つまり、クライアント B に通知します。クライアント B は Zookeeper から通知を受信した後、自分が作成した一時シーケンス ノード 002 が現在の Key1 ディレクトリ内で最もシーケンス番号が小さい一時シーケンス ノードであるかどうかを判断します。この時点で、シーケンスノード 001 は存在しなくなっているため、002 が最小であることは明らかであり、クライアント B はロックを正常に取得します。

図6

同様に、クライアント B がロックを解除すると、002 が削除されます。002 が削除された後、Zookeeper はクライアント C に通知します。クライアント C は、現在作成した一時シーケンス ノード 003 が Key1 ディレクトリ内で最小のシーケンス番号であることを検出するため、クライアント C はロックを正常に取得します。

考える

クライアント A がロックを正常に取得した後、長時間ロックを解放しないか、クライアント A が配置されているマシンがクラッシュするか、クライアント A が配置されているマシンでネットワーク障害が発生します。この時何が起こるのでしょうか?

クライアント A が配置されているマシンがクラッシュしたり、ネットワーク障害が発生したりして、Zookeeper との通信が長時間行われない場合、クライアント A と Zookeeper の間に作成されたセッションは無効になります。このセッションが無効になると、Zookeeper はクライアント A によって作成された一時シーケンス ノードを直接削除します。この時点で、他のクライアントは正常にロックを取得できます。

<<:  Kubernetes を本番環境で 2 年間使用して学んだ教訓

>>:  [Sticky JVM] 5年ぶりにJVMのロードメカニズムを知る時が来ました!

推薦する

検索エンジンからすぐに好まれる方法

「Google やその他の検索エンジンで上位にランクされるには、Web サイトが有用かつ関連性が高く...

基礎知識はSEOの魂

SEO 担当者は、毎日「SEO」という 3 つの単語を見ると、少し美的疲労を感じるかもしれません。実...

SKYCC統合マーケティングソフトウェア:通常のマーケティングソフトウェアよりも使いやすい

電子商取引は急速に発展しており、オンラインマーケティングもそれに応じて変化しています。新興の人気産業...

インターネット マーケティングでは、無料のプロモーションと有料のプロモーションのどちらを選択すべきでしょうか?

月給5,000~50,000のこれらのプロジェクトはあなたの将来ですマーケティング業務に携わる友人の...

vpsdimeはどうですか?シアトルデータセンター VPS リアルレビュー、Netflix/TikTok のブロックを解除可能

vpsdime の特徴は、依然として大容量メモリと 10Gbps の帯域幅を備えた OpenVZ7 ...

リースウェブ - 年末50%オフ/サーバー/VPS/CDN/仮想ホスト/複数のコンピュータルーム

1997年に設立された老舗ブランド、leasewebが年末にプロモーションを実施。サーバー、VPS(...

lovevps-$7/KVM/2g メモリ/25gssd/1T トラフィック/フロリダ

lovevps は、SSD ハードドライブ、2G メモリ、25g SSD を使用する KVM vps...

月収2万元のSEOになる方法 - Rebirth

以前、「月収2万のSEOになる方法 - 初心者編」や「月収2万のSEOになる方法 - どん底に落ちた...

#クリスマス# スピンサーバー: 月額 289 ドル、米国サンノゼ/ダラス、2*e5-2683v4/512gDDR4/8tSSD/10Gbps 帯域幅

今年のクリスマスに向けて、spinserversはダラスとサンノゼのデータセンターの専用サーバーの特...

メールマーケティングをうまく行うには、「段階的な進歩」に注意を払う必要があります

電子メール マーケティングをうまく行うにはどうすればよいでしょうか。これは多くの企業が知りたいことで...

server.ua: ウクライナの VPS、ウクライナのサーバー、無制限のトラフィック、苦情防止

ウクライナのホスティング プロバイダーである server.ua は、2005 年に設立されました。...

旅行統合企業Ctrip:Qunarの買収は困難、eLongへの投資を希望

テンセントテクノロジーファン・シャオドンが5月12日に報じた。 CtripとQunarの合併・買収交...