DUICUO

10年間の建築家の古典的な要約:Zookeeperを学ぶ原則

[[275518]]

I. ZooKeeper とは何ですか?

ZooKeeperは、サービス検出、分散ロック、分散リーダー選出、構成管理などに利用される分散コーディネーションサービスです。これらはすべて、Linuxファイルシステムに似たツリー構造(軽量なインメモリファイルシステムと言えるものの、少量の情報の保存にしか適しておらず、大量のファイルや非常に大きなファイルの保存には全く適していません)を提供するZooKeeperをベースにしており、各ノードの監視と通知のメカニズムも提供しています。ファイルシステムであるため、ZooKeeperがどのようにデータの一貫性を確保しているかを理解することが不可欠です。

II. ZooKeeper クラスタアーキテクチャ


ZooKeeper クラスタは、マスター・スレーブ型レプリケーションに基づく高可用性クラスタです。通常、マスターサーバーはプライマリサーバーとして書き込みサービスを提供し、他のスレーブサーバーはマスターサーバーから最新のデータを非同期的に取得して読み取りサービスを提供します。ZooKeeper は従来のマスター/スレーブの概念を採用しておらず、リーダー、フォロワー、オブザーバーという3つの役割を導入しています。各役割は以下のタスクを実行します。

  • ZooKeeper クラスタには、一度に 1 つのリーダーしか存在しません。リーダーは、すべてのフォロワーとオブザーバーとの間でハートビートを開始および維持します。すべての書き込み操作はリーダーを介して完了する必要があり、リーダーは書き込み操作を他のサーバーにブロードキャストします。
  • フォロワーは、ZooKeeper クラスタ内のフォロワーであり、複数のフォロワーを持つ場合があります。フォロワーはリーダーのハートビートに応答します。フォロワーはクライアントからの読み取りリクエストを直接処理して返す一方で、書き込みリクエストはリーダーに転送して処理させることができます。また、リーダーが書き込みリクエストを処理する際に、フォロワーは書き込みリクエストに対する投票(「多数決書き込み成功」戦略)も行います。
  • オブザーバーの役割はフォロワーの役割に似ていますが、投票権はありません。

ZooKeeper はクラスター内のマスターとスレーブ間のデータの一貫性をどのように確保しますか?

書き込み操作の一貫性と可用性を確保するために、ZooKeeper はクラッシュリカバリをサポートする一貫性プロトコル「Atomic Broadcast (ZAB)」を採用しています。このプロトコルに基づき、ZooKeeper はマスター・スレーブ方式のシステムアーキテクチャを実装し、クラスター内のレプリカ間でデータの一貫性を維持します。

データ書き込み時の一貫性を確保するため、ZookeeperクライアントはZookeeperクラスタ内のノードにランダムに接続します。読み取り要求の場合は、現在のノードから直接データを読み取ります。書き込み要求の場合、現在のノードがリーダーノードでない場合は、そのノードはリーダーノードにトランザクションをコミットします。リーダーノードはトランザクションをブロードキャストし、半数以上のノードが書き込みに成功した場合、書き込み要求はコミットされます(2PCプロトコルと同様)。

サーバー操作中のリーダー選出(リーダーがクラッシュした後に新しいリーダーを選出する方法)?

ZooKeeper クラスタモードでは、リーダーノードに障害が発生してもサービスの継続的な提供には影響しません。ただし、リーダーノードに障害が発生すると、新しいリーダーノードを選出するプロセスが一時的に停止します(この点が ZooKeeper と Eureka の違いです)。

  • クラスターに既にリーダーが存在する場合、別のサーバーが追加されます。クラスター内に既にリーダーが存在する場合、これは通常、クラスターが正常に動作する前にマシンが起動されたことを意味します。この場合、マシンがリーダーを選出しようとすると、現在のリーダー情報が通知されます。マシンはリーダーマシンとの接続を確立し、状態を同期するだけで済みます。
  • クラスタリーダーに障害が発生し、新しいリーダーを選出する必要がある場合(例:server3 に障害が発生した場合)、残りの各サーバーは投票を行います。Server1 と Server2 はそれぞれ、リーダーを宣言するための投票を行います。各投票には、候補サーバーの myid と ZXID が含まれ、(myid, ZXID) と表されます。この場合、Server1 の投票は (1, 0)、Server2 の投票は (2, 0) です。各サーバーは、その投票をクラスタ内の他のマシンに転送します。新しいリーダーが選出された後、次のステップとして、すべてのノードがリーダーと整合性のあるデータを持つように、データ同期が行われます。

投票の処理。各投票について、サーバーは他のユーザーの投票と自身の投票を比較する必要があります。比較ルールは以下のとおりです。

  • ZXID のチェックを優先します。ZXID が大きいサーバーがリーダーとして優先されます。
  • ZXIDが同じ場合は、myidを比較します。myidが大きいサーバーがリーダーサーバーになります。

ZooKeeper クラスターを形成するには奇数台のサーバーを使用するのが最適なのはなぜですか?

ZooKeeper には、クラスター内のマシンの半数以上が正常に機能している限り、クラスター全体を外部から利用できるという特性があります。つまり、ZooKeeper インスタンスが 2 つあり、そのうちの 1 つが故障した場合、過半数ではないため (1 > 3/2)、クラスター全体が使用不可になり、2 つの ZooKeeper インスタンスの故障に対する許容度は 0 になります。同様に、ZooKeeper インスタンスが 3 つあり、1 つが故障して 2 つが正常な場合、過半数である (2 > 3/2) ため、3 つの ZooKeeper インスタンスの故障に対する許容度は 1 になります。ZooKeeper インスタンスが 4 つあり、2 つに障害が発生した場合、まだ 2 つが残っています (2 ≤ 4/2)。これは明らかに過半数ではないため、クラスターは依然として使用不可であり、4 つのインスタンスの許容度は依然として 1 になります。したがって、偶数個の ZooKeeper インスタンスをデプロイできないわけではなく、偶数では高可用性にあまり貢献せず、サーバー スペースの無駄になります。

III. ZooKeeperの重要な概念

ZooKeeper はデータをメモリに保存するため、高いスループットと低いレイテンシが保証されます (ただし、メモリによって保存できるデータの量が制限されるため、znode に保存されるデータの量を比較的小さく保つもう 1 つの理由となります)。

ZooKeeper は高性能です。特に、書き込み処理では全サーバー間で状態を同期する必要があるため、読み取りが書き込みを上回るアプリケーションでは高いパフォーマンスを発揮します。(読み取り中心のシナリオは、コーディネーションサービスでよく見られます。)

セッション

セッションとは、ZooKeeper サーバーとクライアント間の接続を指します。ZooKeeper では、クライアント接続はクライアントとサーバー間の永続的な TCP 接続です。クライアントが起動すると、まずサーバーとの TCP 接続を確立します。この接続が確立された瞬間から、クライアントセッションのライフサイクルが始まります。この接続を通じて、クライアントはハートビートチェックによってサーバーとの有効なセッションを維持し、ZooKeeper サーバーにリクエストを送信して応答を受信し、サーバーから Watch イベント通知を受信することができます。sessionTimeout 値は、クライアントセッションのタイムアウト期間を設定するために使用されます。サーバーの過負荷、ネットワーク障害、またはクライアントによる接続の切断によってクライアント接続が失われた場合、sessionTimeout 期間内にクラスター内のいずれかのサーバーに再接続する限り、以前に作成されたセッションは有効なままです。

サーバーは、クライアントのセッションを作成する前に、まず各クライアントにセッションIDを割り当てます。セッションIDはZooKeeperセッションの重要な識別子であり、多くのセッション関連メカニズムはこのセッションIDに基づいているため、どのサーバーからでもクライアントに割り当てられるセッションIDがグローバルに一意であることを保証することが不可欠です。

ウォッチャー

ウォッチャー(イベントリスナー)はZooKeeperの重要な機能です。ZooKeeperでは、ユーザーが特定のノードにウォッチャーを登録することができ、特定のイベントがトリガーされると、ZooKeeperサーバーは関心のあるクライアントにイベントを通知します。このメカニズムは、ZooKeeperの分散コーディネーションサービスに不可欠です。

ACL

Zookeeper は、UNIX ファイルシステムのアクセス制御と同様に、ACL(アクセス制御リスト)ポリシーを使用してアクセス制御を行います。Zookeeper では、以下の 5 種類の権限が定義されています。


IV. ZooKeeperのデータ構造

ZooKeeperは、標準的なファイルシステムに似た、階層的な共有名前空間を介して分散プロセス間の連携を可能にします。名前空間はZooKeeper内のデータレジスタ(znode)で構成され、ファイルやディレクトリに相当します。ストレージ用に設計された一般的なファイルシステムとは異なり、ZooKeeperのデータはメモリに保存されるため、高いスループットと低レイテンシを実現できます。


1. PERSISTENT - この永続ディレクトリ ノードは、クライアントが ZooKeeper から切断された後も存在し続けます。

2. PERSISTENT_SEQUENTIAL - 永続的な連番ディレクトリ ノード: クライアントが ZooKeeper から切断された後もノードは存在し続けます。ZooKeeper はノードの名前に連番を割り当てるだけです。

3. クライアントが ZooKeeper から切断されると、EPHEMERAL 一時ディレクトリ ノードが削除されます。

4. EPHEMERAL_SEQUENTIAL - 一時的な連番ディレクトリ ノード: クライアントが ZooKeeper から切断されると、このノードは削除されます。ZooKeeper はノードの名前に連番を割り当てるだけです。

V. ZooKeeperの役割

1. ネーミングサービス

ZooKeeperファイルシステム内に、一意のパスを持つディレクトリを作成します。tborgを使って上流プログラムのデプロイマシンを特定できない場合、下流プログラムとパスを合意し、そのパスを介して相互に探索・検出を行うことができます。

2. 構成管理

プログラムは常に設定を必要としますが、複数のマシンにデプロイされている場合、各マシンで設定を変更するのは困難です。そこで、これらの設定をすべてZooKeeperに取り込み、特定のディレクトリノードに保存しましょう。関連するすべてのアプリケーションはこのディレクトリノードをリッスンします。設定情報が変更されると、各アプリケーションはZooKeeperから通知を受け取り、新しい設定情報を取得してシステムに適用します。

3. クラスター管理

クラスター管理は、基本的に、マシンが参加するか離脱するかと、マスターを選出するかという 2 つの点に要約されます。

まず、すべてのマシンは親ディレクトリ「GroupMembers」の下に一時ディレクトリノードを作成し、親ディレクトリノードの子ノードへの変更をリッスンすることに同意します。マシンがダウンすると、ZooKeeperへの接続が失われ、一時ディレクトリノードが削除され、他のすべてのマシンに兄弟ディレクトリが削除されたことが通知されます。これにより、すべてのマシンがマシンがオフラインになったことを認識します。新しいマシンを追加する場合も同様で、すべてのマシンに新しい兄弟ディレクトリが追加されたことが通知されます。

2 番目の点に関しては、少し変更を加えることができます。すべてのマシンに対して一時的に連番のディレクトリ ノードを作成し、その都度、番号が最も小さいマシンをマスターとして選択します。

4. 分散ロック

ZooKeeperの一貫性のあるファイルシステムにより、ロックの問題はより容易に解決できます。ロックサービスは、排他性の維持とタイミングの制御という2つのカテゴリに分けられます。

最初のタイプでは、ZooKeeper の znode を `createznode` メソッドを使用して実装されたロックとして扱います。すべてのクライアントは `/distribute_lock` ノードの作成を試み、正常に作成したクライアントがロックを取得します。使用後は、`distribute_lock` ノードを削除するとロックが解除されます。

2つ目のタイプでは、/distribute_lockが事前に存在します。すべてのクライアントは、その下に一時的な連番のディレクトリノードを作成します。マスターの選択と同様に、最も小さい番号のノードがロックを取得し、使用後に削除されるなど、利便性を考慮した処理が行われます。