Skip to content

Instantly share code, notes, and snippets.

@murayama
Created July 9, 2013 01:54
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save murayama/5954057 to your computer and use it in GitHub Desktop.
Save murayama/5954057 to your computer and use it in GitHub Desktop.
ZooKeeperについて調査

ZooKeeperについて調査

ZooKeeperとは

分散協調サービス
部分障害を安全に処理できる分散アプリケーションを構築するための一連のツールを提供する
設定情報の集中管理や名前付けなどのサービスを提供する
ZooKeeperのアーキテクチャでは高可用性を冗長サービスにより提供している
クライアントはあるZooKeeperノードへの問い合わせが失敗したらほかのノードに問い合わせることができる
データの更新はマスターノードだけが行うようになっているので、データがノード間で矛盾した内容になることはない(ただし、最新のデータではない可能性はある)
更新を担当するマスターノードが何らかの理由で停止した場合には各ノード間で選挙を行い新たなマスターノードが選出される
ZooKeeperはデータを階層的な名前空間に保存しているが、これはファイルシステム等のデータ構造に似ている
クライアントはこのノードに読み書きを行うことによって、設定情報共有などのサービスを提供する

ZooKeeperに対する理解としては、
高可用性のファイルシステムを提供するものと考えられる

特徴

  • シンプルである
    いくつかの簡単な操作と、加えて順序づけや通知といった抽象化機構を公開する小さなファイルシステムである
  • 表現力に富む
    ZooKeeperのプリミティブ群は協調するデータ構造とプロトコルの大規模なクラスを構築するために使われる豊富なビルディングブロックの集合
    例)
    分散キュー
    分散ロック
    ピアグループからのリーダー選出
  • 高可用である
    マシンの集合上で動作し、高可用であるように設計されているのでアプリケーションはZooKeeperに依存することができる
    ZooKeeperを使うとシステムに単一障害点を作ることを避けることができる
  • 疎結合のやりとりを容易にする
    相互に認識しあう必要のない参加要素同士のやりとりをサポートする
    例えば、お互いの存在をしらないプロセス同士がお互いを見つけ出しやりとりをする為のランデブー機構として使うことができる
    集団を協調させる作用は一度に行えるとは限らない、ZooKeeperにメッセージを残したプロセスはそのメッセージがほかのプロセスによって読み出されたときには、すでにシャットダウンしているかもしれない
  • ライブラリである
    一般的な協調パターンの実装と処方のオープンソースの共有リポジトリ
    プログラマは一般的なプロトコルを自分自身で書く手間から解放される
  • 高性能である
    Yahoo!のベンチマークによると、ZooKeeperのスループットは書き込み主体の負荷において、毎秒10000回以上の操作数になる
    読み込み主体の負荷の場合は、スループットはその数倍になる

ZooKeeperのサービス

データモデル

ZooKeeperは実際のファイルやディレクトリはもっていないがznodeと呼ばれるノードに関する統一的な概念を持っている
znodeはデータ(ファイル)やほかのznodeのコンテナ(ディレクトリ)として振る舞う
znodeは階層的な名前空間を形成する
znodeはデータを保持し、自身に関連づけられたACLを持つ zookeeperは大規模なデータの保存の為ではなく、協調処理のために設計されているため、任意のznodeに保存できるデータの上限は1MBになる
データアクセスはアトミックに行われる
znodeはパスで参照される

一時znode

znodeは2種類、一時もしくは永続のどちらかになる
種類は作成時に決定され、変更は不可
一時znodeはそれを生成したクライアントのセッションが終了するとZooKeeperによって削除される
永続znodeはクライアントのセッションに結びついておらず、クライアントから明示的に削除されない限りは削除されない
一時znodeは子ノードをもつことができない
一時znodeはクライアントセッションに結びついているが、すべてのクライアントから参照することができる(ACLのポリシーによる)
一時znodeは何らかの分散リソースが利用可能になったことを知る必要があるアプリケーションを構築するのに理想的である

シーケンス番号

シーケンシャルznodeはZooKeeperによって名前の一部にシーケンス番号を与えられているノード
シーケンシャルフラグをたてて生成されたznodeの名前には一貫してインクリメントされるカウンターの値(親のznodeによって管理)が追加される
シーケンス番号は分散システムで生じたイベントのグローバルな順序づけに使うことができ、順序をクライアントが推測するために使うこともできる

ウォッチ

ウォッチを使えばクライアントはznodeに何らかの変化があったことを通知してもらうことができる
ウォッチはZooKeeperサービスの操作によって設定するもので、サービスに対する他の操作によってトリガされる
ウォッチがトリガされるのは一度だけである
何度も通知を受け取る場合は、ウォッチを都度再登録する必要がある

操作

ZooKeeperには9つの基本操作がある

操作 説明
create znodeを作成する(親znodeは存在していなければならない)
delete znodeを削除する(znodeは子を持っていてはならない)
exists znodeが存在しているかを調べ、メタデータを取得する
getACL,setACL znodeのACLの取得/設定を行う
getChildren znodeの子のリストを取得する
getData,setData znodeに関連づけられたで0他の取得/設定を行う
sync クライアントのznodeのビューをZooKeeperと同期させる

ZooKeeperでの更新操作には条件がある
deleteあるいは、setData操作では、更新するznodeのバージョン番号を指定する必要がある
バージョン番号はexistsをよんで取得する
バージョン番号が一致しなかった場合は更新は失敗する
更新はブロックしない操作なので、更新に失敗したクライアントはもう一度更新を試みるか、他の処理を行うか決定することができ、その際に他のプロセスの処理をブロックしてしまうこともない
ZooKeeperはファイルシステムと見なすこともできるが、単純化の為に取り払われているファイルシステムの基本機能もある
ファイルは小さく、全体としての読み書きだけしかできないので、オープン、クローズ、シークといった操作は提供する必要がない

API

ACL

実装

ZooKeeperサービスの動作モードは2種類ある
スタンドアローンモードではZooKeeperサーバーが一つだけ動作しており、単純なことからテストには便利であるが高可用性や耐久性は保証されない
実稼働時は、アンサンブルと呼ばれる複数マシンで構成されるクラスタ上で複製モードで動作することになる
ZooKeeperはレプリケーションを通じて高可用性を実現し、アンサンブルの過半数のマシンが動作している限りはサービスを継続する
このことから、アンサンブルの構成は通常奇数にする
ZooKeeperは、znodeのツリーに対して加えられた変更がアンサンブルの過半数に複製されることの保証する
それにより、仮に半分に満たないマシンが障害を起こした場合、最低でも1台のマシンは最新の情報を保持していることになる
この場合、残りのレプリカも最終的には最新の状態に追いつく

  • リーダー選出
    アンサンブル中のマシン群は、リーダーと呼ばれる特別なメンバーの選出をオーケーな宇
    他のマシンは追従者と呼ばれる
    このフェーズは過半数(あるいは定足数)の追従者がリーダーと状態を同期できた時点で終了する

  • アトミックブロードキャスト
    すべての書き込みリクエストはリーダーに転送され、リーダーは、その更新を追従者群にブロードキャストする
    過半数の追従者がその変更を保存したら、リーダーはその更新をコミットし、クライアントは更新が成功したことを知らせるレスポンスを受け取る
    合意を形成するためのプロトコルはアトミックになるように設計されているので、変更は成功するか失敗するかのどちらかになる

リーダーに障害が起きた場合、他のマシンはもう一度リーダー選出を行い、選出されたリーダーとともにそれまでち同様に処理を継続する
障害を起こしたリーダーが後ほど復帰した場合、そのマシンは追従者としてスタートすることになる
リーダーの選出は非常に高速に行われ、公表された結果によrば200msほどしかかからないので、選出の間も目立ったパフォーマンスの低下は起こらない
アンサンブル中のすべてのマシンは更新内容をまずディスクに書き込み、その後でインメモリのznodeツリーのコピーを更新する
読み取りリクエストはどのマシンでも応答することができ、メモリを参照するので高速に処理される

一貫性

ZooKeeperの実装の基本を理解することは、ZooKeeperサービスによる一貫性の保証を理解するのに役立つ
アンサンブル中のマシンに対する「リーダー」や「追従者」といった語は言い得て妙で、大量の更新があった場合は、
リーダーに対して、追従者が遅れをとることがある点をうまく表現している。
これは、変更がコミットされるには、アンサンブル上の過半数のマシンがその変更を保存すればよいということから起こる結果
クライアントには実際にはリーダーに接続されていてもかまわないが、特にリーダーに接続するような制御ができるわけではない
接続しているのがリーダーであることを知るすべもない
znodeツリーに対して行われたすべての更新にはzxid(ZooKeeper Transaction ID)と呼ばれるグローバルにユニークな識別子が与えられる
更新の順序は守られるので、zxidのz1がz2よりも小さい場合、ZooKeeperによれば、z1はz2より先に起きた更新ということになる
ZooKeeperは分散システムにおける順序づけを司る唯一の存在であり、以下のデータ一貫性を保証するように設計されている

  • 順序の一貫性
    任意のクライアントから送信された複数の更新はその送信された順序に従って適用される
    つまり、あるクライアントがznode z の値をaに更新し、その後の操作でzをbに更新した場合、どのクライアントからもzの値がbに見えたあとにaに見えることはないということ

  • アトミック性
    更新は成功か失敗かのどちらかになる
    更新が失敗した場合、クライアントからは一切その更新データは見えることはないということ

  • 単一のシステムイメージ
    クライアントからは、どのサーバーに接続しているかということに関係ない句、同じようにシステムが見えることになる
    これは、あるクライアントが同じセッション中に新しいサーバーに接続したとしても、先に接続していたサーバーから見えていたシステムの状況よりも古いシステムの状況が見えることはない
    あるサーバーに障害は発生し、クライアントがアンサンブル中の他のサーバーに接続する場合でも、障害を起こしたサーバーに追いついていなかったサーバーはそのクライアントからの接続を受け付けない

  • 耐久性
    更新が成功すれば、その更新は保存され、取り消すことができない
    これは、更新はサーバーの障害があっても、それに耐えて残るということ

  • タイムライン
    任意のクライアントから見えるシステムの奏すに起こりえる時間差には限度が設けられているので、数十秒単位以上の遅れが生じることはない
    これは、クライアントに対して非常に古いデータを見せてしまうよりは、サーバーは接続をシャットダウンすることを選択し、強制的にクライアントをより新しいデータを持っているサーバーに切り替えさせるとうこと

パフォーマンス上の理由から、読み出しはZooKeeperのサーバーのメモリだけでまかなわれ、書き込みのグローバルな順序づけには関係しない
この性質の為、ZooKeeperの機構を通さずに通信をしてくるクライアントからは、ZooKeeperの状態は一貫したものに見えないことになる
例えば、クライアントAがznodeのzデータをaからa'に更新し、AがクライアントBに対してzのデータを読み出すように指示し、Bが読み取ったzの値がa'ではなくaだったとする
これは、ZooKeeperの保証する事項にまったく矛盾しない
ZooKeeperが保証していないこの条件は、「クライアントのビュー間における並列一貫性」と呼ばれる
こういった状況が起こらないようにする為には、Bがzから値を読み出す前にzに対してsyncを呼ぶ必要がある
sync操作は、Bが接続しているZooKeeperのサーバーを強制的にリーダーに追いつかせるのでBが読み出す値はAが更新した値と同じになる

ZooKeeperのインストールと実行

インストール

$ cd /usr/local/src
$ sudo wget http://ftp.meisei-u.ac.jp/mirror/apache/dist/zookeeper/zookeeper-3.4.3/zookeeper-3.4.3.tar.gz
$ sudo tar xvfz zookeeper-3.4.3.tar.gz
$ cd zookeeper-3.4.3/

実行

$ export ZOOKEEPER_INSTALL=/usr/local/src/zookeeper-3.4.3
$ export PATH=$PATH:$ZOOKEEPER_INSTALL/bin

設定ファイルを用意する

$ sudo mkdir /usr/local/zookeeper
$ sudo vim conf/zoo.cfg

設定ファイルの中身
取り急ぎ最低限の設定のみ

tickTime=2000
dataDir=/usr/local/zookeeper
clientPort=2181
  • tickTime
    ZooKeeperにおける時間の基本単位ミリ秒で指定
  • dataDir
    データの保存場所、どこでもいい
  • clientPort
    実行ポート

起動

$ sudo zkServer.sh start

起動確認

$ sudo echo ruok | nc localhost 2181

コマンドラインツール

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