こんにちは @sonots です。Haikanko OSS化への道と称した Fluentd 連載第六回です。過去の記事はこちら
今回は Haikanko が提供する1つのフィーチャー(SIer 的に言うソリューション!)であるログ収集の機能についてお話したいと思います。

やりたいこと

簡単にいうと syslog-ng の代わりに使いたい。つまり
  • アプリサーバのログを転送して、そのままログ保存サーバのファイルシステム(実際はNFSかもしれないし、そうじゃないかもしれない)に保存したい
  • ログ保存サーバが1台だと不安なので、レプリケーションしておくりたい
実現方法

fluent-agent-lite を agent として利用する場合は、fluent-agent-lite にはレプリケーションして複数サーバに送る機能はないので、1度別の fluentd ノード (deliver と呼ぶことにします)に送って、deliver で out_copy プラグインを使ってレプリケーションした上で、ログ保存の fluentd ノード (archiverと呼ぶことにします)に送信する形になります。

62d23f20.jpg

fluentd を agent として利用すると (便宜上、sender と呼ぶことにします)、out_copy プラグインを利用してログをレプリケーションして複数 archiver に送ることができるようになります。

8c2a246a.jpg

Haikanko では deliver ノードを用意するのが面倒だったので、 後者のアプローチを取ることにしました。

アプリサーバのネットワークトラフィックが archiver の数だけ倍になっているので、アプリサーバに負担をかけたくない場合は、前者の fluent-agent-lite の仕組みのほうがよいのかもしれませんが、deliver ノードにトラフィックが集中するのもどうかなぁ、と思ってこうしています。置き換え対象の syslog-ng も後者のアーキテクチャだったので、同じ仕組みなら問題ないだろうという算段もありました。

設定ファイル(sender)

fluent-agent-lite と fluentd agent の比較 で書いた fluentd agent とほとんど同じなのですが、負荷分散の代わりに out_copy を利用してレプリケーションした上で、out_forward プラグインで複数サーバにデータを送信するようにしています。

<source>
  type config_expander
  <config>
    type tail_asis
    path /var/log/applog
    pos_file /var/tmp/_var_log_applog.pos
    asis_key message
    tag raw.applog.${hostname}
  </config>
</source>
<match **>
  type copy
 
  <store>
    type forward
    flush_interval 1s
    <server>
      host host1
      port 24000
    </server>
  </store>
 
  <store>
    type forward
    flush_interval 1s
    <server>
      host host2
      port 24000
    </server>
  </store>
</match>


設定ファイル(archiver)

tagomoris  先生のFluentdでログ収集「だけ」やる話 を参考に fluent-plugin-file-alternative を利用して実現しています。fluentd 標準の out_file プラグインだと、タグや時間が付いたり、出力がJSONになってしまったりと(今回のケースでは)余計なものが付いてしまいますが、fluent-plugin-file-alternative を使うと受け取ったログ行だけ出力できます。簡単ですね!
<source>
  type forward
  port 24000
</source>

<match raw.applog.**>
  type file_alternative
  path /var/log/applog.%Y%m%d
  output_include_time false
  output_include_tag false
  output_data_type attr:message
  add_newline true
  compress gz 
</match>

と思っていたのですが、以下の設定のように、
<source>
  type forward
  port 24000
</source>

<match raw.applog.**>
  type file_alternative
  path /var/log/applog.%Y%m%d
  output_include_time false
  output_include_tag false
  output_data_type attr:message
  add_newline true
  compress gz 
</match> 

<match raw.applog2.**>
  type file_alternative
  path /var/log/applog.%Y%m%d
  output_include_time false
  output_include_tag false
  output_data_type attr:message
  add_newline true
  compress gz 
</match> 

タグは違うけれど(raw.applog と raw.applog2)、保存先の path が同じ、という設定を書いてしまった場合に、
$ ls /var/log/ | grep applog
/var/log/applog.yyyymmdd.20130412.b4da171215ae3fdd3.log
/var/log/applog.yyyymmdd.20130412.b4da172062a515bb2.log
のように一時ファイルが2つ作られてしまい、rename の処理でエラーが出たり、最終的に /var/log/applog.20130412.gz と  /var/log/applog.20130412.0.gz という2つのファイルに分かれて保存されてしまうといった現象が発生してしまいました。

これはどうも fujiwara 先生のfluentdで複数箇所から同一のファイルに出力するで既知の問題だったようで、そこで解決方法を真似して fluent-plugin-rewrite を利用して、同一のファイル出力する file_alternative 設定は1箇所だけになるように調整しています。

こんなかんじですね。※ タグにパスそのまま入れて動いているんですが、これってアリなんですかね?
<source>
  type forward
  port 24000
</source>

<match raw.applog.**>
  type rewrite
  add_prefix /var/log/applog.%Y%m%d
</match>

<match raw.applog2.**>
  type rewrite
  add_prefix /var/log/applog.%Y%m%d
</match>

<match /var/log/applog.%Y%m%d.raw.**>
  type file_alternative
  path /var/log/applog.%Y%m%d
  output_include_time false
  output_include_tag false
  output_data_type attr:message
  add_newline true
  compress gz
</match>

まとめ

こんなかんじでログ収集ができるようになりました。

Haikanko としては、設定項目から sender と archiver の設定ファイルをループでまわして自動生成してデプロイしているかんじですね。

それでは!