読者です 読者をやめる 読者になる 読者になる

Studio3104::BLOG.new

uninitialized constant Studio3104 (NameError)

fluent-agent-lite と td-agent で、小さくはじめる fluentd


fluentdを使ってみたいけど、「JSONシリアライズしなくていいのに・・・生でいいのに・・・」と思ってなかなか使い出せないというケースはままあるのではないでしょうか。

こんなときに困ってしまうからですよね。

それでも使ってみたい、現存の古臭い解析機構をアクティブにしたまま、徐々にfluentdによる先鋭的なログ解析を始められたらいいなと思っている方、
fluent-agent-lite と td-agent で、fluentd を小さくはじめてみたらいいと思います。

結論を先に言うと、fluent-agent-lite + fluent-plugin-file-alternative + fluent-plugin-file-parser + out_exec_filterの構成でだいたいの場合間違いないです。


小さくはじめて・・・

小さくはじめて、少しずつ活用していくところを目指します。

Apacheのログを例に、こんなことが出来るようになるところまでやってみます。

  • fluentdのプロトコルで、ログサーバにリアルタイムに生ログを転送できるようにする
  • 生ログを保存しつつ、同じログをパースして利用できるようにする
構成例

fluentdと周辺ツール

インストール 特徴など
fluentd gem OS,rbenv,rvmなど、システムにruby環境が必要
td-agent リポジトリを追加して、(yum|apt-get) install ruby環境を内包しているので、システムのruby環境に依存せず非破壊的に導入可能
fluent-agent-lite インストールスクリプト or rpmbuildしてrpmをインストール perlで書かれているが、依存モジュールなどを内包するので、システムのperl環境に依存せず非破壊的に導入可能。生ログファイルをtailし、パース処理せずにログを送信
td-agent-lite - v.11で登場予定。パース処理をしてからログを転送。in_tailとout_forwardだけのtd-agent?

特徴などをざっと。
今回登場するのは、td-agentとfluent-agent-liteです。


生ログをfluentdで送ってみよう

まずは生ログをfluentdのプロトコルでリアルタイムに転送してみるところからやってみます。
この項で、夜間バッチのscpやrsyncを捨てられるようになる(といいですね)。

recipe
  • 送信側サーバ
    • fluent-agent-lite
  • 受信側サーバ
fluent-agent-lite インストール (送信側)

fluent-agent-liteは、perlで書かれて、パースを行わずにfluentdのプロトコルを用いてログを送ってくれるツールです。
単純にログを送るだけならシンプルな設定をすればすぐに使うことができるし、細かいパラメータ調整も出来るスグレモノです。
冗長構成も取れます。

インストール手順等含め、詳しくは作者のtagomorisさんのブログをごらんください。
#fluentd 用ログ収集専用のエージェント fluent-agent-lite 書いた - tagomorisのメモ置き場

僕はrpmを作って各サーバにデプロイして使っています。

td-agent + fluent-plugin-file-alternative インストール (受信側)

fluentdはrubyで書かれています。
rubyな環境ではruby環境を用意しなくてはならないし、rubyな環境であっても、バージョンが古かったりなどした場合には少し大変です。
td-agentは、自分の中にruby環境を内包してfluentdを動かしてくれるので、ruby環境を用意しなくても、非破壊的かつ簡単にfluentdをはじめることができます。

インストールはリポジトリを追加してパッケージをインストールするだけ。簡単。
Installing td-agent for Redhat and CentOS
Installing td-agent for Debian and Ubuntu

td-agentが入ったら、fluent-gemコマンドでfluent-plugin-file-alternativeを入れます。
fluent-gemコマンドのパスは環境によって異なるので注意。

# /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-file-alternative
fluent-agent-lite 設定 & 起動 (送信側)

単純にログを送るだけのシンプルな設定です。環境に合わせて調整する場合はtagomorisさんのgithubを見るといいです。
また、タグにホスト名を埋めてますが、このへんはchefとかでよしなにやるといいと思います。(plackで設定ファイルを動的に・・・とかって話を誰かがしていたような気もするけど忘れた)

# vim /etc/fluent-agent-lite.conf
TAG_PREFIX="apache"
LOGS=$(cat <<"EOF"
access.app01 /var/log/httpd/access_log
error.app01  /var/log/httpd/error_log
EOF
)
PRIMARY_SERVER="log_server:24224"
# /etc/init.d/fluent-agent-lite start

デフォルトでは、/tmp/fluent-agent.logにログを吐きますので、起動したら異常がないか確認しましょう。
異常がない場合は何も吐かない(はず)です。
詳しいログが必要な場合は、設定ファイルに'LOG_VERBOSE="yes"'を追記して起動するといいですね。

td-agent 設定 & 起動 (受信側)

受信側の設定です。

# vim /etc/td-agent/td-agent.conf
<source>
  type forward
</source>
<match apache.access.**>
  type file_alternative
  path /tmp/httpd/access.*.log
  time_slice_format %Y%m%d
  output_include_time false
  output_include_tag false
  output_data_type attr:message
  add_newline true
</match>
<match apache.error.**>
  type file_alternative
  path /tmp/httpd/error.*.log
  time_slice_format %Y%m%d
  output_include_time false
  output_include_tag false
  output_data_type attr:message
  add_newline true
</match>
# /etc/init.d/td-agent start
Starting td-agent:                                         [  OK  ]

td-agentのログは、/var/log/td-agentに出力されます。
'Starting td-agent:[ OK ]'と表示されてもエラーログが出ている場合があるので、起動したら必ずログを確認しましょう。
異常がない場合は、概ねこんな感じで吐かれているはず。

2012-08-24 11:56:37 +0900: starting fluentd-0.10.25
2012-08-24 11:56:37 +0900: reading config file path="/etc/td-agent/td-agent.conf"
2012-08-24 11:56:37 +0900: adding source type="forward"
2012-08-24 11:56:37 +0900: adding match pattern="apache.access.**" type="file_alternative"
2012-08-24 11:56:37 +0900: adding match pattern="apache.error.**" type="file_alternative"
2012-08-24 11:56:37 +0900: listening fluent socket on 0.0.0.0:24224
確認

ここまでで、app01サーバから、log_serverサーバに生ログを送ることが出来るようになりました。
更新がアクティブなログにはハッシュ値が付与され、更新が停止すると除外されます。
今まで保存していたログとファイル名が違うので解析スパゲッティスクリプトたちが使えなくなってしまうとお嘆きかも知れませんが、内容はしっかりまんま生ログなのでどうにかなるでしょう。

# cd /tmp/httpd
# ls -lrt
total 68916
-rw-rw-rw- 1 td-agent td-agent  3270233 Aug 24 00:10 error.20120823.log
-rw-rw-rw- 1 td-agent td-agent 58868447 Aug 24 00:10 access.20120823.log
-rw-rw-rw- 1 td-agent td-agent   193356 Aug 24 14:45 error.20120824.b4c7f94e7f34b2191.log
-rw-rw-rw- 1 td-agent td-agent  8142756 Aug 24 14:45 access.20120824.b4c7facd8e6800702.log

もう日次バッチのscp,rsyncを捨てられますよね。


生ログを保存しつつ、パースもする

せっかくfluentdを使うのだから、ログをパースして、データをカウントしてグラフにしたり*1、シングルノードでオンメモリで収まるサイズに限定してキャッシュストレージとして使うには最強と噂のMongoDBにデータをストアしたいとか考えるのが普通ですよね。

fluent-plugin-parserを使う

fluent-agent-liteで送られてくるデータは、'message'というキーがついています。
例としてaccess_logを対象とし、'message'キーのデータをパースして、別のファイルに書きだしてみます。

access_logのフォーマットは、一般的なcombinedの末尾にレスポンスタイムを足した形式とします。

LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %D" combined

td-agent.confを修正します。
type copyを用いて、生ログを保存しつつ、パースも行います。

# vim /etc/td-agent.conf
<match apache.access.**>
  type copy
  <store>
    type file_alternative
    path /tmp/httpd/access.*.log
    time_slice_format %Y%m%d
    output_include_time false
    output_include_tag false
    output_data_type attr:message
    add_newline true
  </store>
  <store>
    type parser
    add_prefix parsed
    format /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)" (?<response>[^ ]*))?$/
    time_format %d/%b/%Y:%H:%M:%S %z
    key_name message
  </store>
</match>

<match parsed.apache.access.**>
  type file
  path /tmp/httpd/parsed.apache.access
</match>

<match apache.error.**>
  type file_alternative
  path /tmp/httpd/error.*.log
  time_slice_format %Y%m%d
  output_include_time false
  output_include_tag false
  output_data_type attr:message
  add_newline true
</match>

書き換えたら、td-agentを再起動します。ログの確認をお忘れなく。

# /etc/init.d/td-agent restart
Shutting down td-agent:                                    [  OK  ]
Starting td-agent:                                         [  OK  ]
確認など

parsedなログも出力できました。

# cd /tmp/httpd
# ls -l parsed.apache.access*
-rw-rw-rw- 1 td-agent td-agent 1558669 Aug 24 16:45 parsed.apache.access.20120824.b4c7fdf692fb075d5

噂のMongoDBに書き込みたければ、'parsed.apache.access.**'なデータを処理してるところにtype mongo〜って書いてやればよいわけですね。
非常に汎用性があって素晴らしいですね。


さらに細かいパースをさせたい

ou_exec_filterを使うといいです。
fluentd out_exec_filter を使ってみた - Studio3104::BLOG.new


生ログもとっておきたくて、さらに色々やってみたいとかだったら、とりあえずアプリケーションサーバにはfluent-agent-liteだけ入れておけば間違いないですね。
アプリケーションサーバにtd-agentを入れていろいろやらせるとなると、パースなどの処理で負荷が上乗せされることになるし*2、変更があったときにデプロイするのめんどくさいし*3

さらに細かく何かやりたくなったら、受信側のtd-agentで処理させてあげればいいんじゃないかなと思っています。
アプリケーションサーバよりは台数も少ないだろうし、デプロイも比較的容易でしょう。

それじゃあマサカリ待ってるわね。enjoy!!

*1:リンク先では、メッセージ全体を正規表現にかけてデータをカウントする例を載せていますが、しっかりパースしてから該当のキーだけをカウントさせたほうが効率がだいぶいいはずなので注意

*2:たいていの場合はたいしたことないのだけれど、わずかな負荷増がやばい場合もあるよね

*3:chefとかpuppetすらめんどくさいのです