fluentd の out forward の secondary を S3 にして信頼性を向上する
オートスケールするサーバ(web、アプリ)に立てている fluentd(以下、sender) から、
ログ集約用の fluentd(以下、aggregator) にデータを送るとき、
aggregator がデータを受け付けられないと sender で buffer すると思います。
この状態でスケールイン(ディスクごとサーバを削除)すると、
buffer していてもデータをロストしてしまいます。
そこで、sendor から aggregator に送れない場合は Amazon S3 に送ることができたのなら、
信頼性を向上できるのではないかと考え実験しました。
検証環境
fluentd 0.12.22
fluent-plugin-s3 0.6.6
ruby 2.3.0
注意点
sender から aggregator にデータを送れない状況を再現するために、
server には fluentd を起動していないホストを指定します。
存在しないホストを指定すると fluentd の起動に失敗するので、存在するホストを指定してください。
file buffer
buffer したデータを比較するため、まず file buffer の実験を行います。
以下の様な設定ファイルで fluentd を起動します。
以下の様に fluent-cat
でデータを送ります。
$ echo '{"foo": "bar"}' | fluent-cat debug.test
buffer は msgpack なようなので decode するスクリプトを用意しました。
decode すると以下の様になります。
$ ruby unpack.rb /path/to/forward.debug.test.xxx.log [1459155557, {"foo"=>"bar"}]
s3 buffer
次は S3 に buffer できるかの実験です。
以下の様な設定ファイルで fluentd を起動します。
実験のため、retry_limit
と max_retry_wait
を非常に短くしています。
起動できたら file buffer の時と同じようにデータを送ります。
$ echo '{"foo": "bar"}' | fluent-cat debug.test
S3 を見るとデータが保存されていました。
送れていることが確認できたのならば、file buffer のときと同じく復元できるか確認します。
$ aws s3 cp s3://path/to/buffer/forward_debug.test.gz . $ gunzip forward_debug.test.gz $ ruby unpack.rb /path/to/forward.debug.test [1459155737, {"foo"=>"bar"}]
復元できました。
タイムスタンプ以外は同じ結果になったので、
aggregator を復旧すれば buffer からデータを再送できると思います。
まとめ
out forward の secondary を S3 にすることができるか検証しました。
検証に使った設定ファイルのままでは使えないと思いますので調整する必要はあると思いますが、
buffer をロストしにくくできそうですね。
実際に使用する場合は、S3 の buffer からデータを送り直す手順を確認しておくと良いと思います。
primary と secondary の type が違うのは推奨していないようで、
type of secondary output should be same as primary output primary="Fluent::ForwardOutput" secondary="Fluent::S3Output"
のような warn が出力されます。
secondary を S3 にした場合は問題なさそうな挙動でしたが、
他の plugin ではどうなるかわかりませんのでご注意ください。
プロセスのメモリ使用量とCPU使用率などが取れる mackerel-plugin-linux-proc-stats をリリースしました
プロセスのメモリ使用量と CPU 使用率などのメトリクスが取れる、
mackerel-plugin-linux-proc-stats をリリースしました。
Installation
https://github.com/tkuchiki/mackerel-plugin-linux-proc-stats/releases
からバイナリをダウンロードして解凍してください。
Usage
$ ./mackerel-plugin-linux-proc-stats --help Usage of ./mackerel-plugin-linux-proc-stats: -follow-child-processes Follow child processes -metric-key-prefix string Metric key prefix -pid string PID -pidfile string PID file -tempfile string Temp file name -version Version
このプラグイン独自のオプションを説明すると、
pid
: PID を指定pidfile
: PIDファイルの pathfollow-child-processes
: 子プロセスまで集計するか
となっています。
follow-child-processes
について説明するために実行例を示します。
nginx の master と worker プロセスが各1つずつ起動しているとします。
その状態で master プロセスの情報だけ取得する場合は、以下のように実行します。
$ ./mackerel-plugin-linux-proc-stats -pidfile /var/run/nginx.pid nginx_process.cpu.usage 0.000000 1458808477 nginx_process.memory.vsize 107450368.000000 1458808477 nginx_process.memory.rss 3399680.000000 1458808477 nginx_process.num.running 0.000000 1458808477 nginx_process.num.processes 1.000000 1458808477 nginx_process.num.threads 1.000000 1458808477
master と worker プロセス両方の情報を合算して取得する場合は、以下のように実行します。
$ ./mackerel-plugin-linux-proc-stats -pidfile /var/run/nginx.pid -follow-child-processes nginx_process.num.running 0.000000 1458808496 nginx_process.num.processes 2.000000 1458808496 nginx_process.num.threads 2.000000 1458808496 nginx_process.cpu.usage 0.000095 1458808496 nginx_process.memory.vsize 215269376.000000 1458808496 nginx_process.memory.rss 7966720.000000 1458808496
子プロセスまでしか追わないので、孫プロセスは対象外です(実装するか検討中)。
メトリクスについて
このプラグインは、/proc/PID/stat
を parse しています。
num.running
: 3番目が R かどうかnum.processes
: 指定したプロセスのプロセス数(follow-child-processes
をつけた場合は子プロセス含む)num.threads
: 20番目の値cpu.usage
: 15, 16 , 17, 22番目の値 とプロセスの起動時間、uptime、getconf CLK_TCK
の値を使って計算memory.vsize
: 23番目の値memory.rss
: 24番目の値
num.running
については、実行時間が長い処理を行わない限りは R にならないので、0 の場合がほとんどです。
/proc/PID/stat
の例を載せておきます。
10440 (nginx) S 1 10440 10440 0 -1 4202816 71 0 0 0 0 0 0 0 20 0 1 0 364149088 107450368 830 18446744073709551615 1 1 0 0 0 0 0 1073746048 402745863 18446744073709551615 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
IAM の Switch Role を捗らせる
AWS のクロスアカウントアクセスを利用すると、
IAM ユーザを AWS アカウントごとに作成しなくても良くなり管理が容易になるのですが、
Switch Role する アカウントが多いと、履歴が 5 件しかないのでアカウントとロールを再入力しなくてはならないことが増えてきます。
ロールを切り替えるユーザーアクセス権限の付与 を見ると、
とあります。
Alias は以下を例にすると Your_AWS_Account_ID
です(参考: AWS アカウント ID とその別名)。
https://signin.aws.amazon.com/switchrole?YourAccount=hogehoge&roleName=YourRole
にアクセスすると、
アカウントとロールが入力された状態でアクセスすることができます。
また、ロールの切り替え(AWS マネジメントコンソール) を見ると、
とあり、 displayName
を指定すると表示名も入力した状態にできます。
また、color=カラーコード
で色を指定することもできます。
指定できる色は左から順に、
- F2B0A9 (何も指定しなくてもこれになります)
- FBBF93
- FAD791
- B7CA9D
- 99BCE3
です(右端の黒は指定方法がわかりませんでした)。
color についてはドキュメントに書いていないようでしたので、
変更される可能性があります。
最後に、account, roleName, displayName, color を全部指定した場合の例を示します。
https://signin.aws.amazon.com/switchrole?account=YourAccount&roleName=YourRole&displayName=YourDisplayName&color=99BCE3
にアクセスすると、
すべて入力済みになります。
この URL をブックマークしておくと、各項目を入力しなおさなくても良くなるので便利です。
まとめ
Switch Role の URL の query string に、
- account = alias または account ID
- roleName = ロール名
- displayName = 表示名
- color = カラーコード
を指定すると、各項目を入力済みの状態にできるので便利です。
setusergroups の RPM spec ファイル
setusergroups については、作者の tokuhirom さんのブログを御覧ください。
supplementary groups をサポートする setuidgid であるところの setusergroups.c 書いた
supplementary groups をサポートした setuidgid が欲しいケースがある。
これを相談されたので RPM の spec ファイルを書きました。
以下を ~/rpmbuild/SPECS/setusergroups.spec
として保存して、
curl -L https://github.com/tokuhirom/setusergroups/archive/master.zip > ~/rpmbuild/SOURCES/master.zip rpmbuild -ba ~/rpmbuild/SPECS/setusergroups.spec
で RPM を作成できます。
autoconf
のバージョンが 2.68 以上でないと build できないので、
CentOS 6 で build する場合は base repo 以外のものを使う必要があります。
norikra-listener-zabbix 0.2.0 をリリースしました
norikra-listener-zabbix (rubygems) 0.2.0 をリリースしました。
変更点
group
の記述を変更
port
を廃止し、ZABBIX_SERVER:[PORT]
と記述するようになりました。
-- group ZABBIX(localhost:10051, zabbix host)
のように記述します。
IPv6 サポート
IPv6 に対応しました。
-- group ZABBIX([::1]:10051, zabbix host)
のように、[ ]
で IPアドレスをくくらないとエラーなります。
group
の prefix_item_key
を省略可能に
prefix の指定が必須ではなくなりました。
指定しない場合は、列名がそのままアイテムキーとして使用されます。
列の別名に .
を使いたい場合、$
を指定すると .
に置き換えてアイテムキーとして使用します。
なぜこのような仕様になっているかというと、
Identifiers cannot contain the "." (dot) character, i.e. "vol.price" is not a valid identifier for the rename syntax.
とあるように、.
が使えないので、Zabbix のアイテムキーとして使えない文字列かつ列の別名に使える記号として $
を採用しています(あまり美しくないですが...)。
例は以下のとおりです。
SELECT sum(foo) AS `bar$foo$sum`, avg(foo) AS `bar$foo$avg` FROM test_table.win:time_batch(1 min)
参考
Norikra の集計結果を直接 Zabbix に送る norikra-listener-zabbix をリリースしました
追記(2016/02/08 15:30):0.2.0 で group
の記述方式を変更しましたので、
norikra-listener-zabbix 0.2.0 をリリースしました をご確認ください。
Norikra から直接 Zabbix にデータを送る norikra-listener-zabbix (rubygems) をリリースしました。
Zabbix へデータを送信するコードのほとんどは、
fujiwara/fluent-plugin-zabbix を使わせていただきました。ありがとうございます。
Installation
gem install norikra-listener-zabbix
Norikra をインストールした gem で gem install すれば自動で有効になります。
Usage
Group を以下のように設定します。
ZABBIX(zabbix_server, zabbix_host, preifx_item_key, [port=10051])
- zabbix_server:
localhost
- zabbix_host:
test server
- prefix_item_key:
nginx
の場合は、以下のとおりです。
ZABBIX(localhost, test server, nginx)
prefix_item_key については、アイテムキーの prefix です。
port は Zabbix Server デフォルトの 10051 を使っている場合は省略できます。
利用例
秒間のリクエスト数を HTTP ステータスコードごとに集計する場合を考えます。
SQL
ステータスコードごとに COUNT
して秒間のデータにします。
SELECT COUNT(1, 200 <= status AND status <= 299) / 60 AS rate_2xx, COUNT(1, 300 <= status AND status <= 399) / 60 AS rate_3xx, COUNT(1, 400 <= status AND status <= 499) / 60 AS rate_4xx, COUNT(1, 500 <= status AND status <= 599) / 60 AS rate_5xx FROM nginx_status.win:time_batch(1 min)
Zabbix
アイテム
prefix_item_key とSQL の列名(rate_2xx
など) を .
で連結したアイテムを作成します。
prefix_item_key は nginx
、列名は rate_2xx
, rate_3xx
, rate_4xx
, rate_5xx
です。
作成するアイテムは以下のようになります。
- タイプ:
Zabbix トラッパー
- キー:
nginx.rate_2xx
,nginx.rate_3xx
,nginx.rate_4xx
,nginx.rate_5xx
- データ型:
数値 (浮動小数点)
1 つの SQL で複数のアイテムにデータを送信することができます。
グラフ
グラフは適宜作成してください。
2xx のデータしかないのであまり良くない例ですが、
それぞれのステータスコードのリクエストが送られてくれば集計されます。
その他
Zabbix 周りのコードはほとんど fujiwara/fluent-plugin-zabbix を使わせていただきましたが、
一部変更した部分があります。
また、実装する上でハマったところがあったのでそのことに触れておきます。
Zabbix 周りの改良点
Zabbix Server にデータを送信すると、
{ "response" => "success", "info" => "Processed 2 Failed 0 Total 2 Seconds spent 0.000103" }
のようなレスポンスが返って来ます。
このとき、info
の Failed が 1 以上だったり、Processed が 0 で全て Failed というケースでも response
は success になります。
Processed が 0 でなければ 1 つ以上データが送れていることになるので良いのですが、
全て Failed した場合は失敗にしたほうがわかり易いと思い、 warn
でログを出すようにしています
(実装している時、ログに何も出ないのにデータが送れていなくて理解するのに時間がかかりました)。
全て Failed になるケースは、以下の 2 つを確認しています。
- Zabbix ホスト名が間違っている
- アイテムキーが間違っている
split(",")
だけだと空白が含まれる
Norikra::Listener::Zabbix.initialize
の argument
を ,
で split するときに、
ZABBIX(zabbix_server, zabbix_host, preifx_item_key)
(わかりにくいですが ,
の後ろにスペースがあります)と書いて、
zabbix host とアイテムキーにスペースが含まれて正常に動作しない問題で1時間くらい嵌まりました...
そこで、スペースを気にしなくても良いように split したあとに strip しています。
def self.parse_argument(args) args.split(",").map(&:strip) end
Listener Plugin を書く方は、この処理をしておくと変なところで嵌らなくて良いのでおすすめです。
まとめ
Norikra Listener Plugin の norikra-listener-zabbix をリリースしました。
是非お使いください!
Consul Multiple Datacenters 検証結果 +α
この記事は、HashiCorp Advent Calendar 2015 17日目の記事です。
検証環境の Consul は、
$ consul --version Consul v0.6.0 Consul Protocol: 3 (Understands back to: 1)
です。
検証環境は v0.6.0
ですが、v0.6.0 に依存した話しはほとんどないと思います。
筆者は、Consul を Multiple Datacenters(以降、Multi-DC) で運用しております。
Multi-DC で Consul を導入する際に検証した結果を記します。
トピックは以下のとおりです。
- WAN
- DC をまたいで DNS を引く
- DC をまたいで KV のデータを取得する
- DC をまたいで KV にデータを入れる
- Consul Event は複数の DC に一斉に送れない
- DNS forward に Unbound を使う
- External Services
準備
Consul のバイナリを入手します。
$ curl -LO https://releases.hashicorp.com/consul/0.6.0/consul_0.6.0_linux_amd64.zip $ unzip consul_0.6.0_linux_amd64.zip
実験のために何台もサーバを立てるのは大変なので、
検証用に 1 台のサーバで consul を複数起動する - tkuchikiの日記 のような手順で、
1 台のサーバに Server x 3, Client x 1 のクラスタを 2セット作ります。
dc01
$ ./consul members Node Address Status Type Build Protocol DC consul01-dc01 10.0.2.15:8301 alive server 0.6.0 2 dc01 consul02-dc01 10.0.2.15:8311 alive server 0.6.0 2 dc01 consul03-dc01 10.0.2.15:8321 alive server 0.6.0 2 dc01 consul04-dc01 10.0.2.15:8331 alive client 0.6.0 2 dc01
$ curl http://127.0.0.1:8500/v1/status/leader "10.0.2.15:8300"
dc02
$ ./consul members -rpc-addr=127.0.0.1:18400 Node Address Status Type Build Protocol DC consul01-dc02 10.0.2.15:18301 alive server 0.6.0 2 dc02 consul02-dc02 10.0.2.15:18311 alive server 0.6.0 2 dc02 consul03-dc02 10.0.2.15:18321 alive server 0.6.0 2 dc02 consul04-dc02 10.0.2.15:18331 alive client 0.6.0 2 dc02
$ curl http://127.0.0.1:18500/v1/status/leader "10.0.2.15:18300"
WAN
WAN は、すべての DC を含めた Consul クラスタ全体のことです。
consul members -wan
は Multi-DC の Consul Server のみを返します。
$ ./consul members -wan Node Address Status Type Build Protocol DC consul01-dc01.dc01 10.0.2.15:8302 alive server 0.6.0 2 dc01 consul01-dc02.dc02 10.0.2.15:18302 alive server 0.6.0 2 dc02 consul02-dc01.dc01 10.0.2.15:8312 alive server 0.6.0 2 dc01 consul02-dc02.dc02 10.0.2.15:18312 alive server 0.6.0 2 dc02 consul03-dc01.dc01 10.0.2.15:8322 alive server 0.6.0 2 dc01 consul03-dc02.dc02 10.0.2.15:18322 alive server 0.6.0 2 dc02
client に向けて consul members -wan
を実行すると、
何も出力せず、status code 2 を返します。
$ ./consul members -rpc-addr=127.0.0.1:8430 -wan $ echo $? 2
DC をまたいで DNS を引く
dc01
の Consul に対して、dc02
の node を問い合わせます。
$ dig @127.0.0.1 -p 8630 consul04-dc02.node.dc02.consul A ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.2 <<>> @127.0.0.1 -p 8630 consul04-dc02.node.dc02.consul A ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19552 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;consul04-dc02.node.dc02.consul. IN A ;; ANSWER SECTION: consul04-dc02.node.dc02.consul. 60 IN A 10.0.2.15 ;; Query time: 1 msec ;; SERVER: 127.0.0.1#8630(127.0.0.1) ;; WHEN: Tue Dec 15 17:58:09 2015 ;; MSG SIZE rcvd: 94
A レコードが返ってきます。
DNS Interface - Consul by HashiCorp に書いてありますが、
<node>.node[.datacenter].<domain>
なので、
同一 DC にいる場合は、 [.datacenter]
を省略することができます。
$ dig @127.0.0.1 -p 8630 consul04-dc01.node.consul A ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.2 <<>> @127.0.0.1 -p 8630 consul04-dc01.node.consul A ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46271 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;consul04-dc01.node.consul. IN A ;; ANSWER SECTION: consul04-dc01.node.consul. 60 IN A 10.0.2.15 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#8630(127.0.0.1) ;; WHEN: Tue Dec 15 18:05:00 2015 ;; MSG SIZE rcvd: 84
DC をまたいで KV のデータを取得する
まず、通常の KV にデータを PUT して取り出す場合です。
dc01
に PUT します。
$ curl -X PUT -d "dc01-test" http://127.0.0.1:8500/v1/kv/dc01 true
$ curl http://127.0.0.1:8500/v1/kv/dc01?raw dc01-test $ curl http://127.0.0.1:8510/v1/kv/dc01?raw dc01-test $ curl http://127.0.0.1:8520/v1/kv/dc01?raw dc01-test $ curl http://127.0.0.1:8530/v1/kv/dc01?raw dc01-test
dc01
内で KV のデータが共有されていますね。
この状態で、dc02
の KV を参照すると、
$ curl http://127.0.0.1:18500/v1/kv/dc01?raw
データが入っていませんね。
これは、仕様なのでおかしい挙動ではありません。
追記: 2016-08-23 19:30
KV をまたいでデータを取得するためには、以下のように dc=
をつければ OK です。訂正致します。
curl -s 'data' http://127.0.0.1:18500/v1/kv/data?dc=dc02&raw"
ちなみに、consul-replicate というものがあるので、
これを使えば KV のデータをレプリケーションすることができます。
しかし、
- consul-replicate をどのサーバで動かすか
- consul-replicate の HA構成はどうするか
- consul-replicate のレプリケーションが一方向なので、DC 間での同期はどうするのか
といった問題があるので、使いどころが難しそうです。
DC をまたいで KV にデータを入れる
追記: 2016-08-23 19:30
curl -s -X PUT -d 'data' http://127.0.0.1:18500/v1/kv/data?dc=dc02"
のように、dc=
をつければ datacenter をまたいで KV にデータをいれることができました。
間違ってた情報を書いていたので、そちらは削除します。
Consul Event は複数の DC に一斉に送れない
consul event
には、-datacenter
というオプションがありますが、
指定できる DC は一つだけです。
複数の DC に Event を送りたい場合は、DC ごとに実行するようです。
Unbound で DNS forward する
Dnsmasq で Consul DNS に forward して内部 DNS に使っている方が多いと思いますが、
Unbound でも forward できます。
# unbound.conf server: access-control: 127.0.0.0/8 allow do-not-query-localhost: no forward-zone: name: "consul" forward-addr: 127.0.0.1@8600
Unbound の設定に明るくなくて、
デフォルトの設定に上記設定を追加したらうまく forward できませんでした...
設定が最低限すぎるので、適宜設定を追加してお使いください。
External Services
Consul Service は、Consul クラスタ内のサービスを監視しますが、
External Services を使うと、外部のサービスを監視することができます。
$ curl -X PUT -d '{"Datacenter": "dc01", "Node": "google", "Address": "www.google.com", "Service": {"Service": "search", "Port": 80}}' http://127.0.0.1:8500/v1/catalog/register true
External Services を使うためには、recursor
または recursors
で DNS サーバを指定しなくてはなりません。
consul01-dc01(port 8600) は recursor
を設定せず、
consul02-dc01(port 8610) は設定しているとします。
その場合、以下の様な実行結果になります。
$ dig @127.0.0.1 -p 8600 search.service.consul ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.2 <<>> @127.0.0.1 -p 8600 search.service.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56306 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;search.service.consul. IN A ;; ANSWER SECTION: search.service.consul. 15 IN CNAME www.google.com. ;; Query time: 0 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Tue Dec 15 19:41:34 2015 ;; MSG SIZE rcvd: 88
$ dig @127.0.0.1 -p 8610 search.service.consul ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.2 <<>> @127.0.0.1 -p 8610 search.service.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26004 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;search.service.consul. IN A ;; ANSWER SECTION: search.service.consul. 15 IN CNAME www.google.com. www.google.com. 149 IN A 216.58.220.196 ;; Query time: 11 msec ;; SERVER: 127.0.0.1#8610(127.0.0.1) ;; WHEN: Tue Dec 15 19:42:01 2015 ;; MSG SIZE rcvd: 118
recursor
を設定した consul02-dc01 は、A レコードが返ってきます。
recursor
の反映は consul reload
ではできませんので、再起動する必要があります。
※追記
recursor を設定していない状態からの反映は consul reload
ではできませんが、
recursor を設定している状態からは consul reload
で変更を反映することができます。
まとめ
Consul の Multi-DC について検証した結果 +α を紹介しました。
使った設定ファイルは https://gist.github.com/tkuchiki/c4ea89df94c8e2a51b83 に置いてあります。
明日は、Multiple DNS recursors の対応ありがとうございます!(http://fstn.hateblo.jp/entry/2015/02/21/024400)
な、@foostan さんです!