Skip to content

Instantly share code, notes, and snippets.

@ndxbn
Last active October 10, 2019 06:37
Show Gist options
  • Save ndxbn/f9fb4c2c5eb7f9c3a948e365caf9796d to your computer and use it in GitHub Desktop.
Save ndxbn/f9fb4c2c5eb7f9c3a948e365caf9796d to your computer and use it in GitHub Desktop.

この記事について

Node.js から Apache ZooKeeper を使うのに必要そうなことを勉強するために、ドキュメントを読んで、自己解釈を書きました。

大体、日本語訳みたいになってると思いますが、正確な単語や表現の選定をするきはありませんし、誤読してる箇所もあるでしょうから、必ず本家ドキュメントも読んでください。

この記事を書いている時点で、Apache ZooKeeper の最新バージョンは 3.5.5 なので、そのドキュメントを読んでいます。 http://zookeeper.apache.org/doc/r3.5.5/

トップページにかかれている、ZooKeeperの説明

ZooKeeper はハイパフォーマンスなコーディネーションサービスをアプリケーションに提供するミドルウェアです。 "naming" "configuration management" "synchronization" "group services" のような機能を、シンプルなインターフェースで提供します。 内部的な "consensus" "group management" "leader election" "presence protocol" は ZooKeeper が勝手にやってくれます。

Overview: 設計コンセプトとアーキテクチャを含むZooKeeperの鳥瞰図

ZooKeeper: A Distributed Coordination Service for Distributed Applications

ZooKeeper は distributed で opens-source な coodination service です。 "synchronization" "configuration maintenace" "groups" "naming" のようなサービスを、シンプルでプリミティブな方法で提供します。 データは、ファイルシステムのようなディレクトリツリー型のデータ構造で管理します。 Java で実装されてます。(※実装はともかく、JVM で動くよって話。)

Design Goals

  • ZooKeeper is simple
  • ZooKeeper is replicated
  • Zookeeper is ordered
  • Zookeeper is fast

ZooKeeper is simple

一般的なファイルシステムのような、階層化された名前空間でデータを管理します。 一つ一つののデータノードを、ZooKeeper では znode と呼びます。 znode は、一つのファイル/フォルダに相当します。 ZooKeeper のデータはすべて im-memory です。

ZooKeeper は、ハイパフォーマンスで高い可用性があり "strictly ordered access" な実装をされています。

  • 大規模分散システムから使えるパフォーマンスを提供します(ハイパフォーマンス)
  • 単一障害点になりません(高可用性)
  • The strict ordering means that sophisticated synchronization primitives can be implemented at the client(strictly ordered access)
    • クライアント側で、同期すべきタイミングを知り、プリミティブな同期する って実装ができるよ、ってこと?わからん
    • たぶん、変更通知のイベントが飛んできたり、矛盾したデータへアクセスされない(トランザクションレベルが SERIALIZABLE)ってことだと思う

ZooKeeper is replicated

ZooKeeper service

全サーバがお互いを認識している必要があります。

  • すべてのServer は、同じ ZooKeeper サービス に参加している他のすべてのサーバを知っている必要があります
  • トランザクションログとスナップショットは永続化されますが、 state (current なデータのこと?)はすべて in-memory image です
  • 大半のサーバー(過半数)が生きていれば、サービス自体は Available です。

ひとつのクライアントは、ひとつの ZooKeeper Server にアクセスします。

  • 通信プロトコルは TCP を使います
    • リクエスト/レスポンス
    • イベントの通知の watch
    • ハートビート
  • コネクションが壊れたら、クライアントは、他のサーバへ再接続しにいきます

Zookeeper is ordered

Zookeeper はすべてのトランザクションに更新順序が採番されます。 その与えられた更新順序を、よりハイレベルで抽象的な目的に利用できます。

Zookeeper is fast

ZooKeeper は「読み取り>書き込み」なワークロードにおいてより高速に動作します。 ZooKeeper は、以下のような条件が揃うような場合が得意です。

  • ZooKeeper を使ったアプリケーションが 1000 台を超えるような台数のマシンで動いていること
  • 読み書きの比率が 10:1 くらいで、読み取りのほうが多いこと

Data model and the hierarchical namespace

ZooKeeper で使える名前空間は、一般的なファイルシステムのそれによく似ています。 ノード名はスラッシュ / で区切られたパスとして識別されます。

ZooKeeper NameSpace

Nodes and ephemeral nodes

一般的なファイルシステムと異なる点は、ZooKeeper の各 Node には、子ノードだけでなく、そのノード自身にもデータを持つことができます。

znode は自身のステータス情報として「そのノードのバージョン番号」「ACL」「タイムスタンプ」などを持っており、キャッシュの検証やデータ更新の調整などに利用できます。 znode のデータが変更されれば、「バージョン番号」はインクリメントされます。 クライアントはデータを取得する際にバージョン番号も得られます。

ノードにあるデータの変更は Atmically に行われます。 各ノードは各々の Access Control List を持ちます。

ZooKeeper には Ephemeral Node という概念があります。 この znode は、作成したセッションがアクティブである限り存在し、セッションが終了すると削除される というものです。 一時ノードの使用例は [TBD]

Conditional updates and watches

ZooKeeper には Watches(監視)という概念があります。 クライアントは znode の変更を watch することができます。 watch は znode の変更によって発火され削除されます。 watch が発火されると、クライアントは znode が変更された旨のパケットを受け取ります。

クライアント・サーバ間のコネクションが切断されると、クライアントは local notification を受け取ります。使用例は [TBD]

Guarantees

ZooKeeper is very fast and very simple. ZooKeeper のゴールは「同期する」という点でより複雑なサービスを構成する基礎になる、ということです。 そのために、以下のような保証を提供します。

  • Sequential Consistency(逐次一貫性): クリアントからの更新は、送信された順序で適用される
  • Atmicity(原子性)
  • Single System Image(単一システムイメージ):クライアントはどの ZooKeeper サーバに接続しても、同じサービスのビューになる
  • Reliability(信頼性):クライアントからの更新はそのまま適用され、その後クライアントから更新されない限り、更新されることはない(サーバサイドのストアドプロシージャやトリガーなどは存在できない)
  • Timeliness(適時性):システムのクライアントビューは、一定の時間内に最新のものである

より深い情報や使用例については [TBD]

Simple API

ZooKeeper の設計のゴールは、めっちゃシンプルな API を提供する、ということです。 その結果、以下のような操作 だけ をサポートすることになりました:

  • create: create a node
  • delete: delete a node
  • exists: test if a node exists
  • get data: reads the data from a node
  • set data: writes data to a node
  • get children: ノードの子ノード一覧を取得する
  • sync: データの変更が ZooKeeper Service 全体に浸透するのを待つ

より深い情報や使用例などについては [TBD]

Implementation

この図は、ZooKeeper Service 内部のコンポーネント図です。 Request Processor 以外のコンポーネントは、各サーバにそれぞれのコンポーネントの replicates があります。

ZooKeeper components

Replicated Databaes は im-memory データベースです。 すべての "更新" は、リカバリ可能にするためにディスクへログとして残され、シリアル化されてディスクに保存され、その後 im-memory データベースに適用されます。 (※ここでいってるのは、MySQL で言うところの general log みたいなのが常にディスクへ書き込まれているよ、という話です。)

クライアントは、ZooKeeper Service の中に存在する一つの ZooKeeper Server に接続し、リクエストを送信します。 Read Requests は、接続したサーバにある Replica から読み込まれます。 変更を伴う Requests は、Agreement Protocol によって処理されます。

Agreement Protocol は、リーダーと呼ばれる、一つの ZooKeeper Service に一つだけあるサーバに "提案" されます。 リーダーは、フォロワー(リーダ以外のすべてのサーバ)に、変更してもいいかを問い合わせ、問題なさそうであれば、変更し、フォロワーにあるデータが更新されます。 (※要するに、ZooKeeper Service 全体での 2相コミット をしているということ)

ZooKeeper は custom atomic messaging protocol を使用しています。(※詳しい話は ZooKeeper Internals に書かれている)

Programmer's Guide: クライアント側のプログラミングガイド

(※本家ドキュメントは、ここまでに書いたことと重なる内容も多く長々と書かれていたり、最後の方は [TBD] になっていたりと、ドキュメントとしてどうんだって状態です。初出な情報を適宜メモ程度に書いておきます。)

ZoKeeper Data Model

znode のデータには、タイムスタンプやバージョンも含むと言いました。 クライアントから更新リクエストを送る場合、更新内容のほかに、どのバージョンに対して更新をするのか、という情報も必要です。 更新リクエストを送ったときに、更新しようとしている znode がすでにそのリクエストで指定されたバージョンよりも新しいバージョンになっている場合、更新は失敗します。

ノードの種類

Ephemeral Nodes: 一時的なノード

前述したとおり。

Sequence Nodes: 自動的に一意なパスにする

znode を create するときに sequencial にすると、パスの終端に %010d なカウンタを追加されます。 カウンタは符号付き4バイト整数なので、2,147,483,647 を超えるとオーバーフローして -2147483648 になります。

Container Nodes

3.5.3 で追加されました。

子ノードがなくなると、そのノード自体も自動的に削除される znode 。(※いつ削除されるかは未定義)

container znodes を作る場合は、子ノードを create するときに KeeperException.NoNodeException プロパティをつければよいです。 /path/to/my という znode が 存在しない状態/path/to/my/node という znode を KeeperException.NoNodeException 付きで create すると、 /path/to/my という名前 Container Node が内部で自動的に作られます。

(※ようするに、 mkdirp ってことだな)

TTL Nodes

PERSISTENT か PERSISTENT_SEQUENTIAL な znode を create した場合、ミリ秒で TTL を設定することができます。 この TTL の間に znode が更新されず、子ノードも存在しない場合、削除されます。(※いつ削除されるかは未定義)

TTL Nodes は、デフォルトでは作成できません。システム起動時に明示的に有効にする必要があります。 有効になっていない場合、 KeeperException.UnimplementedException が throw されます。

Time in ZooKeeper

ZooKeeper は、いくつかの方法で時間的な前後関係を特定できるようにしています。

  • zxid(Zookeeper TransaCTion ID): すべての変更には、zxid があります。 zxid 1 は zxid 2 のトランザクションよりも前に発生したトランザクションです。
  • Version Numbers: 各 znode ごとにある、変更ごとにインクリメントされる値。znode の変更は version 、znode の ACL の変更は aversion という名前で管理されている。
  • Ticks: 内部的に使っているもの。クライアント側では、「最小のセッションタイムアウト」が Tick Time の 2 倍の数として、間接的に知ることはできます(が、知ったところで用途はありません)。
  • Real Time: ただし、これは本当の real time や clock time ではなく、 znode にある timestamp の話です。

ZooKeeper Stat Structu

  • czxid: Created Zookeeper transaCTion ID
  • ctime: Created TIME
  • mzxid: Modified Zookeeper transaCTion ID
  • mtime: Modified TIME
  • pzxid: 一番最近の、直属の子ノードが作られたトランザクションの ID 。孫以下は含まれない。
  • version: その znode のバージョン(変更回数)
  • cversion: 直属の全子ノードの変更回数の合計。孫以下は含まれない。
  • aversion ACL のバージョン
  • ephemeral Owner: if it's not ephemeral node, it'll be zero.
  • dataLength
  • numChildren

ZooKeeper Sessions

Session State Diagram

ZoKeeper Watches

ZoKeeper ACLs

ZoKeeper

Barrier and Queue Tutorial: バリアとキューに関するサンプル

ZooKeeper Recipes: よくある問題に対するハイレベルな解決策

Administrator's Guide: サーバー側の管理者ガイド

Quota Guide: クォーター関連のガイド

Observers: スケーラビリティを向上させるための、リーダー選出に参加しないメンバーノードについて

Dynamic Reconfiguration: サーバの設定を動的に更新するには

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment