たごもりすメモ

コードとかその他の話とか。

#fluentd meetup 3 にいってきた&しゃべってきた

Fluentd meetup #3 #fluentd on Zusaar

開催されたので参加してきた。また td-agent に fluent-plugin-webhdfs がバンドルされるようになった後ということで、それについて話さないかと言われていたのでそういう話をひとつしてきた。
今回の会場はIIJさんの会議室。広くていいなあ。ありがとうございました!

で、話の内容とか参加者の反応を見ていると、もうだいぶ普通に使われるツールになったのかなーという気がする。もうあまり面白ネタとか驚きが無い。LT枠も4枠は結局埋まらなかったみたいだし。
何か面白なプラグインを書いてネタに走る人とかそろそろ出てこないかなーw

あとIIJの人の話す内容を聞いてて、書こうかと思いつつ放置しているプラグインとか改良を放置しているプラグインとかが脳内によみがえってきてまいった。すいませんすいません。pullreqはいつでもお待ちしています。w

しゃべってきた

資料はこれ。

WebHDFSってなんだっけ、何で必要なんだっけ、fluentdからの使われっぷりはどうよ、みたいなことをつらつら。
しかし会場でHadoop使ってる人が3割くらいだったんで、それだけに終始しなかった自分の嗅覚はすごかった。いちおうFluentdの話ということで、みんなもっと mixin を使おう、mixinを書こう、ということも話した。
プラグインは増えてきたけど、みんなゴリゴリ力技というのもさすがにアレなので、共通で必要な細かい処理なんかはmixinの集合でさくっとやっちゃえるようにしたいよね。そうしないとカオスが広がるばかりだし。

そのあと

飲みながらちょっと話してて out_forward の UDP heartbeat はじつはさくっと TCP に置き換えられるんじゃね? という結論になった。
ので書いた。
send blank message as heartbeat over TCP instead of UDP, when configured... by tagomoris · Pull Request #74 · fluent/fluentd · GitHub

#fluentd でアクセスログからメトリクス生成/リアルタイム監視するための設定例

このエントリは ウィークリーFluentdユースケースエントリリレー の参加エントリです。

いろいろアレでアレなときに回ってきて新ネタを思い付く余裕がないので、手元の設定を晒して解説しお茶を濁そうと思います。ユースケース

前提は以下の通り。

  • アクセスログ
    • このサーバに送られてくる前の段階で適当にparseされている(いちおう in_file の apache 互換の名前のはず?)
    • sampling_filter プラグインにより 1/1, 1/10, 1/100 それぞれの割合でサンプリングされている(基本は1/10)
    • いくつかのメトリクス計算を行い、それらをGrowthForecastへグラフ登録、一部のものはリアルタイム監視を行いIRC通知する
  • ping message
    • ping_message プラグイン(および fluent-agent-lite の -P オプション)による ping message もこのサーバに送られてくるので、監視・保存を行う
  • Flow count
    • いくつかのFluentdプロセスについては、それらが処理しているメッセージ数を flowcounter で集計して結果をこのサーバに送っている
    • 単純に GrowthForecast でグラフ化する

で、このFluentdプロセス(1プロセス、冗長化のために2サーバ使用、通常は primary 側のみに送信)で使っている設定ファイルはこちら。これをパーツごとに解説していく。
https://gist.github.com/3971251

解説前に全体像をさくっと図にしてみるかー、と思ってやってみたらこんなになった。(クリックで拡大)

この図で、HostName および Service はそのままWebサーバやFluentdのホスト名、およびWebサービスのサービス名が入る。N はサンプリングされたログについてのサンプリングレートを示すもので sampled.100 だったら 1/100 のレートでサンプリングされたログ、ということ。input pluginは in_forward しかない。output plugin の out_ はすべて省略してある。

ちなみに数種類のFluentdクラスタで構成されるネットワーク全図が以下のような感じで、その右下の色つきの部分が今回ご説明の範囲。

ではいってみよう! なお in_forward については省略。24224でlistenしてるだけだし。

こまごましたものから

flowcounter

先頭に書いてある。

# output to growthforecast directly (none to process about flowcount.**)
<match flowcount.**>
  type growthforecast
  gfapi_url http://gf.local/api/
  service analysis
  section workers
  name_keys count,bytes,count_rate,bytes_rate
  remove_prefix flowcount
  tag_for name_prefix
</match>

単に flowcounter が出力してきたものがやってくるので、必要な項目をGrowthForecastにぶちこんでグラフ化してます。それだけ。

ping message

次はいきなり一番下。

## ping messages
<match ping.**>
  type copy
  <store>
    type ping_message_checker
    tag missing.ping
    notifications __IS_PRIMARY__
  </store>
  <store>
    type file_alternative
    path /var/log/fluentd/ping.%Y%m.log
    flush_interval 1s
    localtime
    output_include_time true
    output_include_tag false
    output_data_type attr:data
  </store>
</match>

## ping missing notification output (to IRC)
<match missing.ping>
  type ikachan
  host ikachan.local
  port 80
  channel admin
  out_keys data
  message Fluentd node down(ping missing): %s
</match>

ping.HostName なタグのメッセージcopyプラグインにかけ、ping_messsage_checker での欠落チェック、および file_alternative でのファイル書き出しを行っている。
file_alternative での書き出しは、どのホストからpingが飛んできているか書き込んでおくことでfluentd*1が起動しているサーバの一覧を作るため。普段から作っているわけではないけど、一覧がほしくなったらここから取り出す。
ping_message_checker は notifications __IS_PRIMARY__ に注目。じつはサーバに設定をデプロイするとき、デプロイ先ホストに応じてここが true になったり false になったりする。この設定をデプロイするサーバは primary と スタンバイ用の secondary で2台ある(両方とも常時 fluentd は起動している)んだけど、たまに primary への UDP heartbeat パケットが落ちて secondary にメッセージが飛ぶときがある。 ping message checker は一度やってきたメッセージのホスト名を覚えていて欠落したときには notification を出すんだけど、secondary にたまたま(primaryが生きてるのに)飛んじゃった ping メッセージのせいで延々警告を出されてはたまらない。なので、secondary のサーバではこれを false にして、ping message の欠落については警告を出さないようにしている。

後半は ping_message_checker が出す警告をIRCに書き込むため ikachan に出力する設定。そのままですね。

アクセスログ

入力の分岐

このサーバで出力しているメトリクスは以下の4種類、ステータスコード種別毎の割合、リファラに対するカウント、レスポンスタイム統計値、レスポンスタイム範囲毎の割合。これらに使うため、最初に out_route を用いて分岐する。
なお out_route はFluentdに入っておらず rubygem として公開もされていない frsyuki 製のもの。適当な場所に置いて Fluentd 起動時に読み込ませる必要がある*2

分岐は以下の設定で行う。なお 10 と入っているところはサンプリングレートで、実際にはサンプリングレート別に3種類書いてある。

<match sampled.10.*>
  type route
  remove_tag_prefix sampled.10
  <route serviceA,serviceB>
    add_tag_prefix referer.count.10
    copy
  </route>
  <route *>
    add_tag_prefix httpstatus.count.10
    copy
  </route>
  <route *>
    add_tag_prefix responsetime.monitor.10
    copy
  </route>
  <route *>
    add_tag_prefix responsetime.count.10
    copy
  </route>
</match>

リファラのカウントは特定サービスでしか行わないのでそれを最初に列挙している。あとは普通に、この後に行う処理ごとに tag prefix をつけているだけ。

リファラのカウント

分岐したなかから、まずリファラをカウントする。カウント対象のパターンは必要なぶんだけ列挙する。

### referer counting
<match referer.count.10.*>
  type datacounter
  tag 10.datacount.referer
  aggregate tag
  input_tag_remove_prefix referer.count.10
  count_key referer
  pattern1 yahoo ^https?://[-.a-zA-Z0-9]+\.yahoo\.co(m|\.jp)(/|$)
  # pattern2 ....
</match>

とりあえず 10 のものしか対象になかったので forest はかましてない*3。まあ内容としてはカウントして流すだけ。

注意すべきなのは、ここでのカウントは1/10でサンプリングされたあとの数値なので、カウント数やカウントレートも 1/10 になっている、ということ。これはあとで amplifier_filter を使って復元する。ここで(この後のものも)サンプリングレートをタグの先頭に持ってきている、のは後で amplifier_filter で処理して remove_prefix すれば本来のタグに戻せるように。

HTTPステータスの割合毎のカウント
### HTTP status counting
<match httpstatus.count.**>
  type forest
  subtype datacounter
  remove_prefix httpstatus.count
  <template>
    unit minute
    output_per_tag yes
    aggregate tag
    output_messages yes
    count_key status
    pattern1 2xx ^2\d\d
    pattern2 3xx ^3\d\d
    pattern3 429 ^429
    pattern4 4xx ^4\d\d
    pattern5 5xx ^5\d\d
  </template>
  <case 1.*>
    tag_prefix datacount.httpstatus
    input_tag_remove_prefix 1
  </case>
  <case 10.*>
    tag_prefix 10.datacount.httpstatus
    input_tag_remove_prefix 10
  </case>
  <case 100.*>
    tag_prefix 100.datacount.httpstatus
    input_tag_remove_prefix 100
  </case>
</match>

ステータスの種類毎にカウント。サンプリングレート毎に出力時に出すタグのprefixを変える必要があるので forest を使っている。
また429だけ分けてカウントしているのは Apache mod_dosdetector で検出した際のステータスコードを 429 にし、これをリアルタイム障害検知の4xxの対象から外すため。あまり大きくないサービスだと1人が429を垂れ流しただけで通知が上がりまくってひどいことになるのでこのようにしている。

なお counter 系ではこの設定でだけ output_per_tag yes している。こうすることでサービス名をタグに含めることが可能になる。なぜこうしているかというと、後から notifier で障害検出をやるときに特定のサービスだけを対象から外したいから。

レスポンスタイム統計値出力
### response time aggregation
<match responsetime.monitor.**>
  type forest
  subtype numeric_monitor
  remove_prefix responsetime.monitor
  <template>
    unit minute
    tag monitor.responsetime
    aggregate tag
    monitor_key duration
    percentiles 50,90,95,98,99
  </template>
  <case 1.*>
    input_tag_remove_prefix 1
  </case>
  <case 10.*>
    input_tag_remove_prefix 10
  </case>
  <case 100.*>
    input_tag_remove_prefix 100
  </case>
</match>

レスポンスタイムについて、分単位で平均/最小/最大および50,90,95,98,99の各パーセンタイル値を出力。
これは入力はサンプリングレート毎に tag prefix が異なるため forest を使っているが、出力については(実数カウントではなく統計値なので)特にサンプリングレート毎に分ける必要はない。

レスポンスタイム毎の割合
### response time counting
<match responsetime.count.**>
  type forest
  subtype numeric_counter
  remove_prefix responsetime.count
  <template>
    unit minute
    aggregate tag
    count_key duration
    pattern1 u100ms      0  100000
    pattern2 u500ms 100000  500000
    pattern3 u1s    500000 1000000
    pattern4 u3s   1000000 3000000
    pattern5 long  3000000
  </template>
  <case 1.*>
    tag numcount.responsetime
    input_tag_remove_prefix 1
  </case>
  <case 10.*>
    tag 10.numcount.responsetime
    input_tag_remove_prefix 10
  </case>
  <case 100.*>
    tag 100.numcount.responsetime
    input_tag_remove_prefix 100
  </case>
</match>

レスポンスタイム毎の割合を時間範囲毎にカウント。カウントしたメッセージ数(実数)も出力されるのでサンプリングレートを tag prefix に付けて出す。

サンプリング済みログからの出力結果の補正

amplifier_filter を使い、サンプリング済み数値を本来の数値に補正して出力、tag prefix からサンプリングレートを除去する。

### amplifying sampling data counting numerics
<match 10.datacount.**>
  type amplifier_filter
  ratio 10
  remove_prefix 10
  key_pattern .*_(count|rate)$
</match>
<match 100.datacount.**>
  type amplifier_filter
  ratio 100
  remove_prefix 100
  key_pattern .*_(count|rate)$
</match>
<match 10.numcount.**>
  type amplifier_filter
  ratio 10
  remove_prefix 10
  key_pattern .*_(count|rate)$
</match>
<match 100.numcount.**>
  type amplifier_filter
  ratio 100
  remove_prefix 100
  key_pattern .*_(count|rate)$
</match>

なお datacounter / numeric_counter は *_count, *_rate のほかに *_percentage もあるが、パーセンテージはサンプリングされていても割合は変わらないので補正対象にはしない。

各メトリクスメッセージのルーティング

ここまでで必要な各メトリクスの数値はできているが、これを最終的にどこに出力するかを決めるため再度 out_route にかける。

### output routing into growthforecast and notification generation
<match datacount.httpstatus.**>
  type route
  remove_tag_prefix datacount
  <route **>
    add_tag_prefix gf
    copy
  </route>
  <route **>
    add_tag_prefix notify
    copy
  </route>
</match>

その後でかける処理によって gf. とか notify. とかprefixをつける形。HTTPステータスはGrowthForecastへのグラフ出力、および4xx/5xxの割合でのリアルタイム障害検出・通知を行うのでこの2つへ分岐する。
これと同様のものが referer, responsetime (monitor/numcount) にもある、が、それらは growthforecast への出力だけしか行わない、が、将来的に配送先が増えることも考えられるので out_route をかまして gf. を付けるようにしている。設定の拡張性は大事ですよ。

GrowthForecastでグラフ出力
### growthforecast output settings
<match gf.httpstatus.**>
  type growthforecast
  gfapi_url http://gf.local/api/
  service accesslog
  section httpstatus
  tag_for name_prefix
  remove_prefix gf.httpstatus
  name_key_pattern .*_(rate|percentage)$
</match>

<match gf.{referer,responsetime}>
  type forest
  subtype growthforecast
  <template>
    gfapi_url http://gf.local/api/
    service accesslog
    tag_for section
  </template>
  <case gf.referer>
    remove_prefix gf
    name_key_pattern .*_rate$
  </case>
  <case gf.responsetime>
    remove_prefix gf
    name_key_pattern .*_(percentage|min|max|avg|percentile_\d+)$
  </case>
</match>

おなじみ out_growthforecast でグラフ出力する。httpstatusはタグにサービス名が埋まっているので他とすこし設定が違うからそのように分けてある。まあみんな GrowthForecast は使ってるから解説はきっといらないはず。

リアルタイム障害検出・通知

HTTPステータスコード毎の割合を見てアラートを上げる設定。ここではステータスコード500番台が返る割合が 11% 以上の場合に警告、30%以上でクリティカル、としている。また400番台も見ていて50%以上で警告、75%以上でクリティカル。
バグのあるコードを気付かずにデプロイしてしまった場合などに大変お役立ちなので、みなさんもぜひこの設定はすると良いと思います。

## generate notifications
<match notify.httpstatus.**>
  type notifier
  default_tag notification.httpstatus
  input_tag_remove_prefix notify.httpstatus
  <test>
    check numeric
    target_key messages
    lower_threshold 10
  </test>
  <test>
    check tag
    exclude_pattern ^internal-proxy$
  </test>
  <def>
    pattern status_5xx
    check numeric_upward
    target_key_pattern ^5xx_percentage$
    warn_threshold 11
    crit_threshold 30
  </def>
  <def>
    pattern status_4xx
    check numeric_upward
    target_key_pattern ^4xx_percentage$
    warn_threshold 50
    crit_threshold 75
  </def>
</match>

## notification output (to IRC)
<match notification.httpstatus>
  type ikachan
  host ikachan.local
  port 80
  channel sysadg
  out_keys pattern,level,message_time,target_tag,value,threshold,target_tag,target_key
  message HTTP %s %s [%s] %s: %s (threshold %s) http://gf.local/view_graph/accesslog/httpstatus/%s_%s
</match>

out_notifier で検出して out_ikachan でIRCに通知させている。

out_notifier は ... ディレクティブにより条件にマッチしたメッセージだけをチェックの対象にすることができる。ここでは datacounter プラグインが何件のメッセージから出力値を作成したかとして出力する messages を見て、1分間に10メッセージ以下しか流れてきていなかった場合にはチェックの対象外としている。これにより規模の小さいサービスの特に夜間帯など、実際のアクセスがほとんど無く、かつ検索エンジンのクローラなどが404を連発するようなケースで通知が発生してしまうのを抑制している。
またもうひとつの test ディレクティブでは特定のサービス(社内用プロキシ)をチェックの対象外にしている。403/404 や 500 系もよく発生するし、実質的にはあまり監視の必要がないため。

出力値はそのままIRCへ。ちょっと便利なポイントとして、IRCへの通知メッセージに対応するGrowthForecastのグラフURLを入れてある。IRCクライアント上でURLをクリックすればすぐ時系列で確認できるように。

まとめ

長い! あとだいぶ複雑だけど、まあ頑張ればこのくらいはできる。
あと設定ファイル中には例外ケースを除いてサービス名をいっさい書いていないのもわかると思う。このため、新しいサービスのログを流すようになってもfluentdの設定変更はいっさいしなくていいようになっている。こういう状況に最初にしておくと運用が大変ラクちん。

これをそのままコピペしてサンプリング済みログを流せばいろいろとはかどるような気もするので、みなさんぜひ挑戦してみてください。頑張れ!

*1:やfluent-agent-lite

*2:-p オプション

*3:1 や 100のものも増えるようなら forest をかまして 1/10/100 のそれぞれに処理する形になる、httpstatus のところ参照

#fluentdの死活監視を ping message + ping message checker で

先日のFluentd meetup #2からこっちFluentdの監視熱が高まっている昨今ですが、みなさんFluentdの監視してますか。暑いですね。
ところで監視といえばプロセス監視とかは当然やってたんですが、まあやっぱりメッセージ飛ばしてみて実際に飛ぶかどうかとか確認したいよねって思いますよね。当然ですよね。

で、当日調子に乗って out_ping_message を書いたものの、いざFluentdの各プロセスからpingを流してみたら毎分数十以上のメッセージが流れてきてファイルに書いても1周目の目視確認すら困難な状況になったので、ちゃんとping message到着してるか(正確には到着しなくなっちゃったものが無いか)をチェックしてくれる out_ping_message_checker を書いて fluent-plugin-ping-message に追加しました。

fluent-plugin-ping-message | RubyGems.org | your community gem host
tagomoris/fluent-plugin-ping-message · GitHub

これにより、たとえば check_interval 3600 としておくと、その一度届いたあとで期間内に一度も ping message が届かないようになったらアラート用のメッセージを emit してくれるようになります。デフォルトでは3回分のアラートメッセージを流したあとで沈黙します。あとはこのメッセージを適当な output plugin で目につくところに流してやればいいわけですね!
ということで手元ではこんな感じで設定。

# 全fluentdでこんな感じの設定
# たいていサーバに複数プロセス立ってるので data に in_forward がlistenしてるポート番号を含めてる
<source>
  type ping_message
  tag ping
  data NODENAME:PORTNUM
</source>
<match ping>
  type forward
  flush_interval 15s
  <server>
    host watcher01.local
  </server>
  <server>
    host watcher02.local
    standby yes
  </server>
</match>

# watcher側でこれを監視する設定
<match ping.**>
  type copy
  <store>
    type ping_message_checker
    tag missing.ping
    notifications yes   # watcher02 側では no にして、稀にpingがそっちに飛んでもアラート出さないよう抑制する
  </store>
  <store>
    type file_alternative  # チェックと同時にファイルに落とす(fluentd起動中のノード一覧がこれで取れる)
    path /var/log/fluentd/ping.%Y%m.log
    flush_interval 1s
    localtime
    output_include_time true
    output_include_tag false
    output_data_type attr:data
  </store>
</match>

<match missing.ping>
  type ikachan               # pingアラートが出たらIRCに流す
  host ikachan.local
  port 80
  channel watching
  out_keys data
  message Fluentd node down(ping missing): %s
</match>

まあみなさん、何も言わずにこの設定を自分のFluentdの設定ファイルにコピペするといいと思いますね。

fluent-agent-lite v0.5

さて Fluentd はこれでいいとして、自分の場合はログの送出は fluent-agent-lite に頼っているので、こいつからも ping message を送れるようにしたい。と思ったので、した。

https://github.com/tagomoris/fluent-agent-lite/tags の v0.5
https://github.com/downloads/tagomoris/fluent-agent-lite/fluent-agent-lite.v0.5.tar.gz

コマンドラインから起動する場合は -P オプション(と-Sオプション)が関係する。設定ファイル+init scriptでの起動の場合は PING_TAG などの行を設定して起動すると ping message の送信が行われることになる。
fluent-agent-lite で複数ファイルからの読み込みの場合は複数のプロセスが立ち上がるので、強制的に ping message の data フィールドの内容を PING_DATA + (スペースを入れて) 読み込みファイルのパス、としてある。こうすればどのファイルを読んでいるプロセスが落ちたのかがping messageを見るだけでわかる。*1

ということで fluent-agent-lite v0.5 はおすすめです。お使いのかたはアップデートをおすすめします。yum install でインストールしなおしても設定ファイルは上書きされないので、ping まわりの設定値は自分で書き足す必要がありますが。

些細な話

ping message まわりの機能、組込みであったらいいなーと思わなくもないですね。pluginじゃなくてfluentdのリポジトリにaddしちゃおうかなー。さすがにアレかなー。どうしよ。

*1:標準入力から読んでいるプロセスが複数ある場合は同じになってしまう。さすがに対応がめんどう……。

fluent-plugin-ping-message released!

Fluentd meetup in Japan 2の会場でFluentdの動作ホストリストアップや監視に関する意識が高まったので、そのためのプラグインをざっくり書いてみた。会場で書き上げたけど何故か既に酔っぱらってた*1のでその場でリリースは控えてた。
今日確認してみたらだいたい問題なさそうなので、さっくりリリース。

fluent-plugin-ping-message | RubyGems.org | your community gem host
tagomoris/fluent-plugin-ping-message · GitHub

普通にオプションなしで起動すると 'ping' というタグがついて 'data' フィールドにホスト名の入ったメッセージが60秒ごとに出力されます。

<source>
  type ping_message
</source>

あとは interval とか tag とか data とかを適当に設定すれば欲しいものが得られるでしょう。きっと。

このメッセージ、とりあえずファイルに書いたりDBに突っ込んだりして、それを外部から見れば、Fluentdが動いてるホストの一覧が取れるでしょうし、一定時間メッセージを送ってきていないホストをリストアップすることで監視とかができるかもしれません。

そういうことをやってくれる output plugin も書こうかと思ったけどちょっと時間なくて後回しにしました。そのうち気が向いたら書きます。誰がが書いてくれるのも大歓迎です。

*1:なぜだろう、不思議ですね

Fluentd meetup in Japan 2 にいってきた #fluentd

Fluentd meetup in Japan #2 #fluentd on Zusaar

ふらふらとお気楽に参加してきた。当方ささやかながらプラグインを作ったりしているので、他のひとがどのように使っているか、どのようなプラグインが他の人によって使われているか、あたりにたいへん興味があったので、そういう話をかなり聞けたのがすばらしく有益だった。主催者の方々、スタッフの方々、会場提供のグリーの方々、ありがとうございました。

以下だらだらとセッションごとに感想めいたものを書く。

「Fluentdの現在と未来」by @frsyuki

会場のFluentd利用者率が6割だか7割だかでびびる。本当に? みたいな。あと日本語ドキュメントなんていらんかったんやー、俺達は間違ってなかったんやー、と安心したりする。*1

Fluentd次期バージョンの話、じつはこれをメインで聞きにいったけど、既にTwitterとかで出ていた話の紹介だった。実装上注意しとく必要がありそうかなって思うところはいくつかあるけど、細かい話だし、おおむね良い感じになりそうだと思う。パフォーマンスについては、機能的に揃ってきたところで一度見ないとなあ。個人的にはマルチプロセス化まわりに大いに期待しているので、どこかで試して必要ならパッチを書くのも辞さない構え。

とはいえ、そんなに急いでない(機能的には Fluentd 現行バージョンでも特別困ってない)ので、じっくり良いものが作られた方が嬉しい感はあるな。「次のバージョンをはやく」っていう感じの人がけっこういたように思うけど、現行バージョン使い込んでみれば、たぶんそんなに困らないと思いますよ。
プラグインのテストドライバの書き直しくらいは現行バージョンあわせのものでやっちゃってもいいかなーと思うけど、ちょっとヒマがないな……。

「Logging Infrastructure in PaaS by Fluentd」by @yssk22 and @wallyqs

CloudFoundryの管理系に手を入れて Fluentd が自動的にインストールされた環境を作るよ、という話? AWSでEC2上に Fluentd を入れるとナイスだよね、という話と同じような系統の話、だと思う。たぶん。集約されたログの参照も独自の何かのツールを経由してって感じのようだったので、HTTPで直接参照できる S3 に較べるとちょっと機能的には魅力が落ちる。

というか、あんまり簡単にも見えなかったし、自分で使いそうにもないし、あんまり真面目に聴いてませんでした。すいません。

「Fluentdを優しく見守る監視事例」by @GedowFather

最近HadoopまわりのblogエントリとかFluentdまわりのエントリとかをblogに書きまくってる @GedowFather さんの話、きわめて面白かった。実際にどういう構成で何を使ってるか、どういう問題に対してどういう対処をしたのか、ということが超具体的に話されていて参考になるので、みなさんもスライドを熟読するのがよいと思います。

Fluentd Meetup #2 発表資料 | 外道父の匠

で、私見をいくつか。

  • 特定 hostname のタグ改変*2を in_forward でやるのはスジ悪だと思う
  • flowcounterの出力を使ってのホストの死活監視について
    • 塩漬サービスのログを監視するのは確かにいろいろ問題がある*3
    • 今なら外部ツール/スクリプトでflowcounterの出力を処理しなくてもFluentdだけでいける
    • flowcounter + numeric-aggregator / numeric-counter + notifier あたりでアラートメッセージ生成が可能ですね

ちなみに fluent-plugin-webhdfs を作者よりもはやく実戦投入したりしてて、すばらしい冒険心だと思いました。今後ともよろしくお願いいたします。バグがあったらぜひフィードバックください。(私利私欲)

あと、Fluentdが動作しているホストのリストが欲しかったり、死活監視は実際にメッセージを流してやってやりたかったりするよなーとセッションを聞いていて思ったところ、昔考えたコンセプトを思い出したので、セッション聞きながらひとつプラグイン作ったりした。(後述)

「Fluentd & Treasure Data でこっそり始めるログ集計」by @mikeda

実際にいかにしてFluentdを導入するか、いかにしてTreasure Dataでログ集計を始めるか、という極めて実践的な内容でやばかった。TD社の回しものではないかと思うくらい素晴らしい内容でTDの契約数がこれを境に跳ね上がっても不思議ではない様相。スライドがまだ公開されていない、見直したいんだけどまだなのまだなの。

あと、表示されていないスライドは心眼で見ることを参加者に要求するという極めてハイスキルな内容だった。新たな芸風が確立された記念的な日と言える。

あれこれ

懇親会は時間がちょっと短くて残念だったが、でもいろんな人と話をした。誰が何をどう使っているかみたいな話を実際にするのはやっぱりためになる。面白い。すばらしい。またぜひこういうイベントが行われてほしいと思う。

というか、そろそろ自分のケースをしゃべりたそうにしてる人がかなり出てきてそうな気がしてるので、Fluentd Casual Talks をまたやろうと思いました。年末くらいを考えてます。会場も内容もまだなーんにも調整してませんが、そのときになったらよろしくおねがいします。

*1:あとで日本語ドキュメントの整備に燃える人達が別途出てきてた、よかった。

*2:testを含むものを通常の処理ルートから除外する、といったものだったみたい

*3:うちでもやってるけど、云々

UPDATE: fluent-plugin-config-expander and fluent-plugin-forest

先日 fluent-plugin-forest を書いたあとpatchをもらって __HOSTNAME__ というプレースホルダをサポートしたりしてた。
で、こないだ config-expander を書いたときに「ホスト名を置換できるプレースホルダを組込みで入れようかな? まあ out_forest あるしいいか……」と思ってスルーしてた、が、forestはoutput pluginにしか使えなくて残念だなーということをこのblogエントリを見て思ったのでした。

fluentdで自ホスト名を自動でタグにするの巻 - アルパカDiary

ということで、config_expander でも __HOSTNAME__ というプレースホルダを展開できるようにしてみた。
ついでにtwitter上で見掛けた「__hoge__ より ${bar} なプレースホルダの方がいい」という意見を取り入れましてどっちでも展開できるようにしてアップデートしたものを config-expander ならびに forest 両方でリリースしておいた。

fluent-plugin-config-expander | RubyGems.org | your community gem host
fluent-plugin-forest | RubyGems.org | your community gem host

ということで、上記blogエントリの設定例は以下のように in_config_expander 一発で書けます。

<source>
  type config_expander
  <config>
    type tail
    format /^(?<date>[^\t]+)\t(?<cpu-usr>[^\t]+)\t(?<cpu-sys>[^\t]+)\t(?<cpu-idl>[^\t]+)\t(?<cpu-wai>[^\t]+)\t(?<cpu-hiq>[^\t]+)\t(?<cpu-siq>[^\t]+)\t(?<la-1m>[^\t]+)\t(?<la-5m>[^\t]+)\t(?<la-15m>[^\t]+)\t(?<mem-used>[^\t]+)\t(?<mem-buff>[^\t]+)\t(?<mem-cach>[^\t]+)\t(?<mem-free>[^\t]+)\t(?<dsk-read>[^\t]+)\t(?<dsk-writ>[^\t]+)\t(?<io-read>[^\t]+)\t(?<io-writ>[^\t]+)\t(?<net-recv>[^\t]+)\t(?<net-send>[^\t]+)/
    path /tmp/dstat.log
    tag dstat.Tclmdrn.__HOSTNAME__ # もしくは dstat.Tclmdrn.${hostname}
  </config>
</source>

べんり!

fluent-plugin-config-expander v0.1.0 released!

世間の Fluentd ユーザのみなさんはFluentdが1プロセスでいったいどれだけ大量のメッセージをさばけるかを実際にご覧になってそのすばらしさに驚いていることと思いますが、もちろん1ノードで処理できるメッセージ数にはいずれ限界があり、メッセージを次段階の処理を行うFluentdに送るときには対象の分散を考えることと思います。

で、カジュアルにスケールさせていったところ out_forward の配送先が10サーバx各8プロセスの合計80ノードになって設定ファイルが爆発したので、設定ファイル内で繰り返しを記述できるプラグインを書いた。

tagomoris/fluent-plugin-config-expander · GitHub
fluent-plugin-config-expander | RubyGems.org | your community gem host

これにより

これが、

<match hoge.**>
  type forward
  num_threads 28
  send_timeout 5s
  flush_interval 1s
  buffer_chunk_limit 8M
  buffer_queue_limit 128
  <server>
    host node01.fluentd.local
    port 24211
  </server>
  <server>
    host node01.fluentd.local
    port 24212
  </server>
  <!-- 77回省略 -->
  <server>
    host node10.fluentd.local
    port 24218
  </server>
</match>

こうなる。

<match hoge.**>
  type config_expander
  <config>
    type forward
    num_threads 28
    send_timeout 5s
    flush_interval 1s
    buffer_chunk_limit 8M
    buffer_queue_limit 128
    <for node in 01 02 03 04 05 06 07 08 09 10>
      <for port in 24211 24212 24213 24214 24215 24216 24217 24218>
        <server>
          host node__node__.fluentd.local
          port __port__
        </server>
      </for>
    </for>
  </config>
</match>

どうよこの圧倒的な威力。DSLなんて大層なものいらんかったんやー。ループさえあればよかったんやー。

タグによりプラグインを動的生成する fluent-plugin-forest と組合せて使えばcaoticに増え続けるプラグインインスタンスの世界をお楽しみいただけます。*1
ノード数が爆発して困っているfluentdユーザのみなさん、ぜひどうぞ。

*1:作者は絶対にそのようなことはすまいと思っています。