すずけんメモ

技術メモです

Fluentd UIが出たので触ってみた

fluent/fluentd-ui https://github.com/fluent/fluentd-ui

Fluentd用のWeb UIが出たようです。試しに触ってみます。

インストール

READMEのとおりですが、

$ gem install fluentd-ui
$ fluentd-ui start
Open http://localhost:9292/ by your browser
default account is username="admin" and password="changeme"

もしくは、

$ git clone https://github.com/treasure-data/fluentd-ui
$ cd fluentd-ui
$ bundle install
$ bundle exec rails s

です。

僕はbundlerでいれることにしました。

-> % bundle exec rails s
=> Booting Puma
=> Rails 4.1.4 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option)
=> Ctrl-C to shutdown server
Puma 2.8.2 starting...
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://0.0.0.0:3000

起動するとログイン画面が出てきます。デフォルト設定はusername: admin, password: changeme です。

f:id:suzu_v:20140801200246p:plain

ログインするとこんな感じで立ち上がります。

f:id:suzu_v:20140801200428p:plain

早速触ってみます。まずはfluentdをインストールします。

f:id:suzu_v:20140801200243p:plain

インストールされましたね。続いて設定をしていきます。こんな感じに今Fluentdがどこからデータを読み取り、どこに出力しようとしているのかがわかりやすく表示されてます。

f:id:suzu_v:20140801200238p:plain

では実際にファイルの入力について編集していきます。入力の「ファイル」をクリックすると、どこからファイルを読み取るかを選択する画面が出てきます。

f:id:suzu_v:20140801200234p:plain

ここでは /var/log/system.log を読み取ることにしました。こんな感じでログをpreviewすることができます。

f:id:suzu_v:20140801201050p:plain

次にファイルを読み取る際の設定をします。ここでは、「どんなフォーマットとしてログを読み取るか」という設定をすることができます。この画面はわかりやすくて便利ですね。今回はsyslog形式なので、formatをsyslogにしています。

f:id:suzu_v:20140801202229p:plain

これで無事設定が変更されました。生成された設定は以下のとおりです。

<source>
  # http://docs.fluentd.org/articles/in_forward
  type forward
  port 24224
</source>

<source>
  # http://docs.fluentd.org/articles/in_http
  type http
  port 9880
</source>

<source>
  type monitor_agent
  port 24220
</source>
<source>
  type debug_agent
  port 24230
</source>

<match debug.*>
  # http://docs.fluentd.org/articles/out_stdout
  type stdout
</match>

<source>
  type tail
  path /var/log/system.log
  tag syslog.test
  format syslog
  time_format %b %d %H:%M:%S
  pos_file /tmp/fluentd--1406888587.pos
</source>

更新するとfluentdが再起動されて設定がreloadされます。fluentd自体の起動logをみてみましょう。

f:id:suzu_v:20140801200145p:plain

ちゃんとtailされているようです。試しにMongoDBにいれてみます。デフォルトではプラグインは入っていないので、いれてみます。これもFluentd UI上から行うことができます。MongoDB用のプラグインをいれてみましょう。インストールボタンを押せば設定できます。

f:id:suzu_v:20140801200141p:plain

インストール済みのプラグインはこんな感じで閲覧できます。

f:id:suzu_v:20140801200119p:plain

設定も追加してみます。mongoの設定は画面から行うことができます。「ソースと出力先の設定」の画面から「MongoDB」をクリックするとこんな感じで設定画面が開きます。

f:id:suzu_v:20140801200116p:plain

設定は結果的にこんな感じになりました。

<match syslog.test>
  type mongo
  host 127.0.0.1
  port 27017
  database fluentd
  collection test
  capped
  capped_size 100m
</match>

設定を追加すると勝手にfluentdがreloadされます。mongo側をみてみましょう。*1

-> % all output going to: /usr/local/var/log/mongodb/mongo.log
mongo
MongoDB shell version: 2.4.8
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
    http://docs.mongodb.org/
Questions? Try the support group
    http://groups.google.com/group/mongodb-user
Server has startup warnings:
Fri Aug  1 19:49:01.275 [initandlisten]
Fri Aug  1 19:49:01.275 [initandlisten] ** WARNING: soft rlimits too low. Number of files is 256, should be at least 1000
> show dbs;
fluentd 0.140625GB

fluentdのdbができてますね。queryしてみます。

# 以下mongo shell
> use fluentd;
switched to db fluentd
> db.test.find()
{ "_id" : ObjectId("53db72001df33a7e96000001"), "host" : "xxx", "ident" : "SystemUIServer", "pid" : "425", "message" : "Impossible to find range of h or H in date format.", "time" : ISODate("2014-08-01T10:54:34Z") }
{ "_id" : ObjectId("53db723d1df33a7e96000002"), "host" : "xxx", "ident" : "SystemUIServer", "pid" : "425", "message" : "Impossible to find range of h or H in date format.", "time" : ISODate("2014-08-01T10:55:34Z") }
{ "_id" : ObjectId("53db727a1df33a7e96000003"), "host" : "xxx", "ident" : "SystemUIServer", "pid" : "425", "message" : "Impossible to find range of h or H in date format.", "time" : ISODate("2014-08-01T10:56:34Z") }

ちゃんとはいってますね。*2

所感

  • さくっとローカルにfluentdの環境作っていろいろプラグイン入れたりログを試しにいれてみたい、というときにさくっとできて良い
    • fluentd本体のインストールやfluentdのプラグインも簡単に入れることができる
    • アプリケーションログをつくるのは手間がかかるけれど、
  • in_tailのUIが便利
    • どんなログを読もうとしているかをプレビューしつつ、tailの設定を書くことができる
      • 実際にどんな風にログが読み取られるかも見つつ、設定を調整することができる。素敵。
    • http://fluentular.herokuapp.com/ で試せるようなこともFluentd UIの中でできます。
  • pluginがうまく入らなかった
    • ものによる。fluentd-plugin-elasticsearchが入らなかった。依存gemをうまくもってこれてないのかもしれない。

Fluentdを触ったことがないという場合でも、さっくりセットアップと設定を行うことができるのではないか思います。ローカルでさくっと試す用途にもよいのではないでしょうか。まだversionも0.10ですので、今後使いやすくなっていくのが楽しみです。

*1:MongoDBのバージョンがちょっと古いですね、手抜きです。

*2:と思ったら日付型が微妙に間違っている旨のメッセージがはいってますね

広告ログ解析基盤にFluentdを使っている話

これはFluentd Advent Calendar 14日目の記事です。

私は現在、VOYAGE GROUPの子会社であるadingoで、DMP cosmiの開発をしています。今日はcosmiでのfluentd利用の話をしようと思います。

DMPについて

過去に勉強会でアドテクまわり及びDMPについて話したのでそれを貼っておきます。ざっというと、いい感じにいろんなログを受けいられるようにして、それらをモニタリングしながら整理して使えるようにする、という役割をもったプロダクトです。

Head First Ad Technology and DMP http://www.slideshare.net/suzuken/head-first-ad-technology-and-dmp

どこで使っているか

ほぼ全てです。構成としては

ログ収集サーバ
      | 
      | out-forward (roundrobin)
      |
中央ストリーム処理サーバ
      |
      | out-plugin (elasticsearch, dynamodb)
      |
   DynamoDB
 ElasticSearch

という形になっています。他にもいくつかapiが用意されており、それらのサーバにも全てfluentd(td-agent)が入っています。どのサーバでもファイルにログを出力したものをin_tailで拾ってきています。既存のログ運用と併用できますし、アプリケーションから直接fluentdプロセスに吐く手段もありますが、fluentdプロセスが落ちていた場合などを考えるとログが落ちなくなってしまうリスクとなりうるためです。とはいえfluentdプロセスが急に息をしなくなった、という場面はいまのところありません。また、カジュアルにfluentdプロセスを再起動したいというのもin_tailにしている理由だったりします。

ログ収集サーバ側ではバッファリングは全てメモリで

ログをいい感じに整理する、という話がありました。ログにも色々なフォーマットがあり、また新しい項目が増えることも多いので、ここはexec_filterを利用して外部プログラムで処理するようにしています。exec_filterを個人的にはとても気に入っていて、それは外部プログラム自体はfluentd以外のところでも利用できるという点にあります。このプログラムは単純に「ログをいい感じのフォーマットに前処理する」ということをやっていて、これはHiveのmapフェーズやHadoop Streamingでも再利用可能な設計になっています。省エネですね。

またログ収集サーバでのバッファリングはメモリで行っています。これはIO waitを避けるという意味もありますが、単純に元のログファイル自体がファイルシステム上にあるため、resume処理をやれば良い、という形になります。なお、この処理系においては、同じログを再送しても問題ない作りになっているので、カジュアルに再送できます。中央ストリーム処理サーバにラウンドロビンで転送しているのも、このへんの背景があるからだったりします。中央ストリーム処理サーバ自体は2台配置していて、流量としてはどちらか片方が落ちても許容できる程度のサーバが配置されています。

中央ストリームから各種データストアへの書き出し

ここはout pluginのelasticsearchとdynamodbを利用しています。elasticsearchはまだ評価中ですが、実データを突っ込んでどう使うかを設計しているというところです。ログに対しては割りと全文検索という手段は使い勝手が良いです。ただどの程度までデータを保持しておくかというあたりや、どの程度事前にメトリクスを作っておくかというところを検証しているようなフェーズです。fluentd側からはout_copyで単純にstreamを分けてあげて、それをelasticsearchに送り込んでいます。

DynamoDBへの書き込みは外部プログラムでやっていたのですが、最近DynamoDBプラグインでやるように変更しました。hash + rangeを扱いやすくするようなパッチを充てています。*1

検証用データの作り方

Fluentd運用で大事になるのが、検証プロセスです。たとえばexec_filter用に新しいプログラムを充てたいときや、新しいプラグインを試す時です。そういう場合には本番環境のログ収集サーバの一部から検証用環境にout_copyで送るようにしています。ここではsamplingするようになっていて、大体1/10程度のログを検証用に利用するようにしています。もちろん本番環境には通常通り全てのログが流れたままになっています。なぜ本番のログを検証用にも利用するかというと、生ログというのは生き物ですので、実データで試さないと性能の傾向などの見積りがしづらいためです。それまでは本番にとりあえず投入して、しばらく放置してから異変に気がつくというようなことをしていたりしましたが、この方法を撮るようにしてから大分捗るようになりました。out_copy素晴らしいですね。

ちなみにこのへんの検証用データの作り方については、AWS re:Invent 2013でLogglyがやっていた方法に似ています。*2 LogglyではKafka + Storm環境で同じようなパターンを作っているようです。

Fluentdを使う上で無くては生きられないもの、それはGrowthForecast

ほんとGrowthForecast無しでは、というくらい重宝してます。基本的にほぼ全てのmatch句においてcopyプラグインを利用しており、それぞれのストリームをflow-counterで収集しています。そしてそれらをGrowthForecastに送信するようにしています。すると各処理レイヤーでの変化が手に取るようにわかります。例えば、以下のような際には基本的にGrowthForecastを見るようにしています。

  • exec_filterでかませたプログラムを変更した場合
  • buffer_chunk_limit, buffer_queue_limit, flush_intervalなどの設定値を変更した場合
  • 新しいプラグインを導入した場合

前に気が付いたのは、out_copyを利用している場合に、前段のstoreで処理が死ぬと次のstoreに流れなくなる、というようなケースです。後々にdeep_copyを知ったのですが、変更した後にどういうことが起こっているかを把握するというのはやはり大事です。まだFluentdの挙動が完全に把握できているわけではないので、どういう振る舞いになっているかを把握しやすくするというのは運用上大切だと思っています。

なお、in_tailでFluentdにinputするのが面倒な場合には、古きよきcrontabにより簡単な集計をした上でGrowthForecastに送信している部分もあります。

細かいTipsとか微妙に考えるのを放置している部分とか使ってから気が付いた想定していなかったこととか今後やりたいこととか

  • もともと出力していたログはcronologでローテートされていた。ので、in_tailでログを食わせる際には-Hでハードリンクにするようにしている
  • flushの間隔を短くすればするほど最終的な書き込みまでの遅延がなくなるわけだけど、そのあたりの実験
  • s3への転送は歴史的事情によりcrontabでやってるんだけど、生ログを圧縮してs3に置くだけならtd-agent-liteを利用したほうがいいのかもしれない。
    • EC2インスタンスが死んだ時にcrontabだとログ失う可能性があるので、なるべくリアルタイムにs3に送っておきたい。でぃすぽーざぼーにしたい。
  • 結局プラグインを使う場合にはいろいろ挙動を見る前にコード読んだほうが分かりやすかったりする
    • ので最近は結局ドキュメントを読まずにコードを読む
  • data-counter + sampling-filter + GrowthForecastでいい感じにメトリクスつくろうと思ってたんけど、全部やろうとすると設定ファイルが盛々になるし管理しにくくなる
    • ので今はelasitcsearch + Kibana3でそのへんのメトリクスはつくればいいかなと思ってる
    • つまるところ、メトリクスを作るのはコストがかかるので、どこまで何を見たいかによるよねという話
    • 裏側はEMRがあるので、パッと時系列でモニタリングしたいのはGrowthForecastとKibana3でやって、それ以外のは基本的にEMRという戦術をとってはいる
  • Amazon Kinesisが出たらそこに流せるようにはしようと思っている

まとめ

まとめると、Fluentdつかってカジュアルにストリーム処理の色んな手段を試しています。あんまり奇をてらったことはしていないつもりです。@katzchang さんも書いていたように、Fluentdは保守的な構成をとることもしやすく、現にまだcrontabで動作している部分が残っていたりしますし、Fluentdでの処理が失敗しても運用上どうにかなるような仕組みになっています。もともとFluentdを使おうとは思っていたのですが、実は最初に身近で使い始めたのは @bash0C7 さんだったりして、なんだかんだそれから社内でも少しずつ使うところが増えていきました。ということで日々楽しくFluentdを利用しております。Fluentdやtd-agentのメンテナの方々やプラグインを公開してくださっている皆様のお陰です。感謝。

以上、Fluentd Advent Calendar 14日目でした。明日は @katsyoshi さんです。

*1:大分安定してきたのでPR予定です。それと、updateItemについても扱えるようにしようと考えています。

*2:参考: re:InventでのLogglyの分散ストリーム処理環境に関するセッションが面白かったのでまとめておく http://suzuken.hatenablog.jp/entry/2013/11/17/224830