こんにちは @sonots です。Haikanko OSS化への道、連載第二回です。1回目はこちら fluent-plugin-grepcounter をリリースしました 〜 Haikanko OSS化への道(1)

今回は fluent-agent-lite と fluentd ベースで設定した agent の比較記事を書いてみようと思います。まだ、調べきれていない所もあるので、間違ってるよ、とか、ここはこうだよ、とかあれば是非ツッコミをいただきたく。

では早速、まずは fluent-agent-lite から

fluent-agent-lite

fluent-agent-lite とは、@tagomoris さんによる fluentd プロトコルに対応した perl の別実装です。ログ収集対象のサーバに agent (ログ送るやつね)としてインストールすることに特化されており、その分 fluentd に比べて小さいです。

使う動機

fluent-agent-lite を利用すると、ログをそのまま次の fluentd に流すことができます。正規表現パースしないため動作が軽く、負荷の高いアプリケーションサーバに同居させてもCPUを使わない、という利点があります。

インストール

rpm を作ってインストールするのが吉です。@riywo さんの fluent-agent-liteのrpm作るだけのshell — Gist. あたりが参考になると思います。

設定ファイル

設定ファイルは次のように記述します。シェルスクリプトで記述できるので、けっこうなんでもアリにできます。設定を1つにまとめたかったので自分はここでファイル作ったりもしてます ^ ^; ちなみに、LOGS に 複数のログファイルを指定した場合、その数だけ fluent-agent-lite プロセスが起動します。

/etc/fluent-agent-lite.conf

# pre-process
mkdir -p /etc/fluent-agent-lite
cat <<"EOF" > /etc/fluent-agent-lite/primary_servers_list.conf
host1:22000
host2:22000
EOF
cat <<"EOF" > /etc/fluent-agent-lite/secondary_servers_list.conf
host3:22000
EOF
# configuration
TAG_PREFIX=raw
LOGS=$(cat <<EOF
syslog.`hostname` /var/log/syslog
fluent-agent.`hostname` /tmp/fluent-agent.log
EOF)
PRIMARY_SERVER_LIST=/etc/fluent-agent-lite/primary_servers_list.conf
SECONDARY_SERVER_LIST=/etc/fluent-agent-lite/secondary_servers_list.conf
LOG_PATH=/tmp/fluent-agent.log

fluentd agent

@yteraoka さん作の fluent-plugin-tail-asis (アズイズ: そのままの意) を利用すると、ログを正規表現でパースすることなく送信することができます。あとはそれを out_forward すると次の fluentd に流すことができるので、fluent-agent-lite に近い形で利用することができます。 ※ 実装はすごくシンプルで、TailInput を継承してパーサーのみ変更しているようですね。すばらしい。

2013.09.30 追記: 最新版の fluentd では in_tail プラグインに format none という、fluent-plugin-tail-asis と同じことをするフォーマットが追加されているのでそちらを利用できます :D

使う動機

fluentd の in_tail プラグインには、fluent-agent-lite にはないログポジションを覚える機能があります。また、out_forward には再送機能などがあるので、ログをできる限りロストしたくない場合に良さそうです。とはいえ、実際に動かしてみると fluent-agent-lite よりは多少CPUを使ってしまう点が欠点です。

インストール

agent に限らず fluentd の話ですが、td-agent という名前で ruby 同梱の deb および rpm パッケージが提供されているので、それを使ってさっくりインストールすることができます。ruby 同梱なのがけっこううれしかったります。 http://packages.treasure-data.com/

設定ファイル

こんな設定ファイルで fluent-agent-lite と同等の機能を実現できるでしょう。

ポイント: fluent-agent-lite では hostname コマンドでやっていたタグへのホスト名の挿入は、fluentd の場合は fluent-plugin-config-expander を利用することで可能ですね。また、fluent-agent-lite での SECONDARY_SERVER_LIST 相当は standby オプションで可能でした。

ドキュメントには書かれてませんでしたが、コードを読んだら実装してありました。

/etc/td-agent/td-agent.conf

<source>
  type config_expander
  <config>
    type tail_asis
    path /var/log/syslog
    pos_file /var/tmp/_var_log_syslog.pos
    asis_key message
    tag raw.syslog_warn_app_name.${hostname}
  </config>
</source>

<match **>
  type forward
  send_timeout 60s
  recover_wait 10s
  heartbeat_interval 1s
  phi_threshold 8
  hard_timeout 60s
  buffer_type memory
  buffer_chunk_size 156
  buffer_chunk_limit 8m
  flush_interval 1s
  retry_wait 1.0
  retry_limit 17

  <server>
    name host1:22000
    host host1
    port 22000
    weight 50
  </server>
  <server>
    name host2:22000
    host host2
    port 22000
    weight 50
  </server>

  <server>
    name host3:22000
    host host3
    port 22000
    weight 50
    standby true
  </server>

  <secondary>
    type file
    path /var/log/td-agent/td-agent-failed.log
  </secondary>
</match>

比較

ここからは、細かい動作仕様の比較をしていきます。

ログファイルの追い方

1. ファイル切り詰め (copytruncate)

ファイルをコピーして元ファイルを切り詰める、いわゆる copytruncate をした場合どうなるかの実験です。

$ cp /var/log/syslog /var/log/syslog.1
$ echo -n > /var/log/syslog

fluent-agent-lite のログメッセージ

/usr/bin/tail: /var/log/syslog: ファイルが切り詰められました

fluentd のログメッセージ

2013-03-15 20:44:13 +0900 [info]: detected rotation of /var/log/syslog; waiting 5 seconds
2013-03-15 20:44:17 +0900 [info]: following tail of /var/log/syslog

どちらも切り詰めたファイルの末尾から再度追ってくれます。

2. rename

ファイルを mv して新しく作った場合はどうなるかの実験です。

$ mv /var/log/syslog /var/log/syslog.1
$ touch /var/log/syslog

fluent-agent-lite

/usr/bin/tail: `/var/log/syslog' has become inaccessible: そのようなファイルやディレクトリはありません
/usr/bin/tail: `/var/log/syslog' has appeared; following end of new file
/usr/bin/tail: `/var/log/syslog' has been replaced; following end of new file

fluentd

2013-03-15 20:49:40 +0900 [info]: detected rotation of /var/log/syslog; waiting 5 seconds
2013-03-15 20:49:51 +0900 [info]: detected rotation of /var/log/syslog
2013-03-15 20:49:51 +0900 [info]: following tail of /var/log/syslog

どちらも新しいファイルを追ってくれますが、ここが一番の違いで、fluentd の場合は、ログの取りこぼしがないように5秒間だけ元のファイルのファイルディスクリプタを追ってくれるようです。

3. シンボリックリンクおきかえ

アプリが連番(もしくは日時付き)のログを吐く場合、fluentd で追えるようにするにはシンボリックリンクを貼って常に同じ名前のログファイルを用意する必要があります。その場合の実験です。

$ ln -s /var/log/syslog.1 /var/log/syslog
↓一定時間後おきかえ
$ ln -s /var/log/syslog.2 /var/log/syslog

fluent-agent-lite

/usr/bin/tail: `/var/log/syslog' has been replaced; following end of new file

fluentd

2013-03-15 20:49:40 +0900 [info]: detected rotation of /var/log/syslog; waiting 5 seconds
2013-03-15 20:49:51 +0900 [info]: detected rotation of /var/log/syslog
2013-03-15 20:49:51 +0900 [info]: following tail of /var/log/syslog

どちらも新しいファイルを追いかけ始めてくれ、新しいファイルは先頭行から読み込んでくれるようです。fluentd は 先ほどと同じく5秒間元のファイルディスクリプタを追います。

4. 存在しないファイルにシンボリックリンクを貼ってみる

ちょっといじわるに存在しないファイルにシンボリックリンクを貼った場合の実験です。

$ ln -sf /var/log/hogehoge /var/log/syslog
↓後でファイルを作ってみる
$ touch /var/log/hogehoge

fluent-agent-lite

/usr/bin/tail: `/var/log/syslog' has become inaccessible: そのようなファイルやディレクトリはありません
/usr/bin/tail: `/var/log/syslog' has appeared; following end of new file

fluentd

2013-03-12 18:57:34 +0900: detected rotation of /var/log/syslog; waiting 5 seconds
2013-03-12 18:58:02 +0900: following tail of /var/log/syslog

どちらも1度ファイルがなくなったと判断した後、ファイルを追いかけ始めてくれました。

5. 同じファイルにもう一度シンボリックリンクを貼ってみる

またちょっといじわるに同じファイルにシンボリックリンクを貼った場合の実験です。

$ ln -sf /var/log/syslog.1 /var/log/syslog
$ ln -sf /var/log/syslog.1 /var/log/syslog

fluent-agent-lite

出力なし

fluentd

2013-03-12 18:56:02 +0900: detected rotation of /var/log/syslog; waiting 5 seconds
2013-03-12 18:56:06 +0900: following tail of /var/log/syslog

fluentd の場合は新しいファイルができたと勘違いしてしまったようです。まぁ、そんなことやらないけど。

まとめ

基本的にどちらもいいかんじです。一番の違いはやはり fluentd の場合は、ログの取りこぼしがないように5秒間だけ元のファイルのファイルディスクリプタを追う所ですね。fluent-agent-lite の挙動は内部で利用している tail コマンドの挙動なので、そちらをすでに把握している人にはわかりやすいと思います。

あとは、明らかなので実験はしませんでしたが、fluentd の in_tail プラグインにはログポジションを覚えておく機能があるので、再起動時に続きからログを読み込むことができます。fluent-agent-lite は内部的に tail -F を利用しているだけなので、再起動時は最新行からの読み込みになりますね。

※ tail -F を利用してログ書き込みがあれば即座に取り込むという fluent-agent-lite の仕組みはだいぶシンプルで cool だと思います。ログポジションを覚えようとすると、その分リソースも使ってしまいますし仕組みも複雑になるので、あえて実装しないのが良手だと思います :D

ちなみに @oranie さんのブログ記事 にあった @frsyuki さんの言を引用させてもらうと fluentd は次のような挙動をするようです。確かにそういう挙動でしたね。データの取りこぼしにかなり気を使っているそうです。

1)新規に設定されたファイルは終端から読む
2)ログローテーションされたら次のファイルを先頭から読む
3)再起動時には前回読み終わった位置から読み始める(位置はファイルに保存しておく) 

ぜぇぜぇ、書くのだいぶ疲れてきましたが、続きます。fluent-agent-lite と fluentd agent の比較(2) 〜 Haikanko OSS化への道(2)