log.fstn

技術よりなことをざっくばらんにアウトプットします。

Consul lock を動かしてみる

お待ちかね Consul 0.5.0 が出ました -> https://hashicorp.com/blog/consul-0-5.html
今回のリリースでいろんな機能が追加されましたが lock が気になったのでとりあえず動かしてみます。

環境準備

Consulと使いそうなツールを幾つか含んだDockerコンテナで検証してみます。

FROM ubuntu:trusty

MAINTAINER foostan ks@fstn.jp

RUN apt-get update && apt-get install -y wget curl unzip telnet dnsutils
RUN wget http://stedolan.github.io/jq/download/linux64/jq
RUN chmod +x jq
RUN mv jq /usr/bin

## consul
RUN wget -P /tmp https://dl.bintray.com/mitchellh/consul/0.5.0_linux_amd64.zip
RUN unzip /tmp/0.5.0_linux_amd64.zip -d /tmp
RUN mv /tmp/consul /usr/bin

複数のターミナルでコンテナ起動

とりあえずサーバ1台と

$ docker run -it foostan/consul /bin/bash
root@a95dafd4c471:/# consul agent -server -bootstrap -data-dir /tmp &

クライアント3台起動します

$ docker run -it foostan/consul /bin/bash
root@730cc2b3a957:/# consul agent -join 172.17.0.34 -data-dir /tmp &
$ docker run -it foostan/consul /bin/bash
root@2804f185fe4a:/# consul agent -join 172.17.0.34 -data-dir /tmp &
$ docker run -it foostan/consul /bin/bash
root@14e9577a1104:/# consul agent -join 172.17.0.34 -data-dir /tmp &

メンバー確認

root@a95dafd4c471:/# consul members
Node          Address           Status  Type    Build  Protocol
a95dafd4c471  172.17.0.34:8301  alive   server  0.5.0  2
730cc2b3a957  172.17.0.32:8301  alive   client  0.5.0  2
2804f185fe4a  172.17.0.33:8301  alive   client  0.5.0  2
14e9577a1104  172.17.0.31:8301  alive   client  0.5.0  2

lock コマンドを使ってみる

ドキュメントが相変わらずしっかりしてるのありがたいですね -> https://consul.io/docs/commands/lock.html

1つのコンテナで consul lock 実行してみます。 -verbose つけると詳細なログが出るので挙動が確認しやすいです。

root@2804f185fe4a:/# consul lock -verbose service/foo/lock "while true; do date; sleep 1; done"
Setting up lock at path: service/foo/lock/.lock
Attempting lock acquisition
Starting handler 'while true; do date; sleep 1; done'
Fri Feb 20 16:41:13 UTC 2015
Fri Feb 20 16:41:14 UTC 2015
Fri Feb 20 16:41:15 UTC 2015
Fri Feb 20 16:41:16 UTC 2015

1秒単位で date の結果が流れ始めます。 この状態で別のノードから同じコマンドを実行してみます。

root@14e9577a1104:/# consul lock -verbose service/foo/lock "while true; do date; sleep 1; done"Setting up lock at path: service/foo/lock/.lock
Attempting lock acquisition

こちらはコマンドが実行されません。 この状態で、先ほど実行していた方を停止してみます。

Fri Feb 20 16:44:42 UTC 2015
^CShutdown triggered, killing child
Terminating child pid 2177
Error running handler: signal: terminated
signal: terminated
Child terminated
Cleanup aborted, lock in use

すると、実行されずに待機していたほうが実行され始めました。

root@14e9577a1104:/# consul lock -verbose service/foo/lock "while true; do date; sleep 1; done"
Setting up lock at path: service/foo/lock/.lock
Attempting lock acquisition
Starting handler 'while true; do date; sleep 1; done'
Fri Feb 20 16:44:42 UTC 2015
Fri Feb 20 16:44:43 UTC 2015
Fri Feb 20 16:44:44 UTC 2015

文字だけだと分かりにくいので動画とりました。

http://f.st-hatena.com/images/fotolife/f/foostan/20150221/20150221032710_original.gif?1424457051

こちらの動画では -n 2 をオプションで付けているため最大2台実行され、それ以降はコマンドを実行してもロックされます。

また途中でコマンドを停止するとロックされていたクライアントから実行するべきノードが選出されて実行されます。

簡単な解説

ロックする仕組み(実行を開始しても待機していた部分)に関しては 0.3.0 で導入されたセッションを利用しています -> http://www.consul.io/docs/internals/sessions.html

また、実行中のクライアントが停止したときに、残りの別のクライアントで再開する部分は、今回のバージョンで新しく追加された client-side Leader Election によって実現されています。

今までLeader Election(リーダー選出)はサーバ間でのみ行っており、クライアントからの要求を受けるサーバを選出するためのものでした。 またそのアルゴリズムとしてRaft(https://consul.io/docs/internals/consensus.html)が利用されていました。

で、今回追加されたのは文字通りクライアント側のリーダー選出の仕組みです。 上記動画では4台のクライアント(厳密には1台はサーバ)のうち2台がコマンドを実行し、2台は待機している状態でした。そして、1台実行を停止して2台のうち1台で実行が開始されましたが、このときにRaftによるリーダ選出が行われるわけです。 利用する側はとくに何も考えずにクライアントが選出されるのでありがたいですね。

Raftがどのようなアルゴリズムになっているかは今後論文を読んで理解を深めたいところです。

Contributeした話

consul lock は関係ないですが、Consulに投げた幾つかのPRをマージしてもらって今回のバージョンで無事リリースされました(OSSへの初PR初マージ)。 注目度の高いプロダクトにContributeすることができて単純に嬉しかったのとOSS活動へのモチベーションが上がりました。
今後も普段利用しているOSSや注目しているOSSへの感謝の気持ちを忘れずに、可能であればContributeを続けて行きたいと思います。

ちなみにマージされたPRの内容は以下の2件です。

Multiple DNS recursors

DNS Interface には recursor という設定項目があって、これはConsul外部の問い合わせがあった時にフォワードする先を指定するもので、

{
    "recursor": "8.8.8.8"
}

などと設定しておくと、Consulで名前解決出来ないものを "8.8.8.8" に問い合わせてその結果を返してくれます。 で、今回送ったPRではこれを複数対応するもので

{
    "recursors": ["8.8.8.8", "8.8.4.4"]
}

という具合に指定できます。 運用しようと思うと地味に必要になってくるかなということで知っておくと案外助かるかもしれません。

参考