たごもりすメモ

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

FluentdでバッファつきOutputPluginを使うときのデフォルト値

なんか自分で docs.fluentd.org へのpatchを書いてて混乱してきたのでまとめる。コードを読んでも関係する設定値がいくつものモジュールに分散しており、完全に把握することが困難である。具体的には、この組合せを記憶だけで答えられる fluentd コミッタはおそらく一人もいない。

概要

対象は BufferedOutput および TimeSlicedOutput を継承している output plugin の全て*1。out_forward, out_exec や out_exec_filter も含まれる。

基本的にはいくつかの設定により flush をするタイミングを制御するパラメータ一式、およびflush対象となるデータのチャンクを溜めておく量の上限を決めることとなる。fluentd をうっかり試したときに「アイエエエ、fluent-cat してみたんだけど、設定したところにログが出力されないよ? fluentd落とすと出てくるよ? ナンデ? フルーエントディーナンデ?」っていう誰もが抱く疑問の答えはここにある。が、おそらくその全てを全output pluginの設定で執拗に指定している人はいないだろう。

またBufferedOutputとTimeSlicedOutputでは挙動がさまざまに異なりデフォルト値も違う。そしてプラグイン側でそのデフォルト値を上書きしているケースもある。まさにすべての設定値がどうなっているのか把握したい厨にとってはfluentdの闇とも言える部分である。

関係する設定項目は以下の通りである。

  • buffer_type
  • buffer_queue_limit , buffer_chunk_limit
  • flush_interval
  • buffer_path (file only)
  • time_slice_format , time_slice_wait (TimeSlicedOutput only)

また注意事項として BufferedOutput のデフォルトの buffer_type は memory であり TimeSlicedOutput のデフォルトは file である。ただしこれを上書きしているプラグインもある(out_webhdfsなど)。

ずばり表をつくってみた

設定値 BufferedOutput + memory BufferedOutput + file TimeSlicedOutput + memory TimeSlicedOutput + file
buffer_queue_limit 64 256 64 256
buffer_chunk_limit 8MB 8MB 256MB 256MB
flush_interval 60 60 nil nil
シャットダウン時 flushされる flushされない flushされる flushされない

つまり TimeSlicedOutput な出力で出力先が詰まっている場合、最大で64GBのバッファファイルが生成されたあとで詰まることになる……! って、意外に普通の数値だったな。TimeSlicedOutput + memory の場合は16GBをメモリに確保してから詰まる。

flush_interval は通常60秒。Fluentdでバッファを使用するプラグインは以下の条件のどちらかを満たした場合にバッファをflushする動作を行う。

  • バッファチャンクのサイズが buffer_chunk_limit に達した場合
  • バッファチャンクが作られてから flush_interval で指定した時間が経過した場合

ただし TimeSlicedOutput の場合は flush_interval がデフォルトで nil なので、以下のような条件のどちらかに変わる。

  • バッファチャンクのサイズが buffer_chunk_limit に達した場合
  • time_slice_format で指定される時間幅の終端に達し、そこから更に time_slice_wait で指定された時間を経過した場合

time_slice_wait のデフォルトはじつは10分(!)なので、流量の小さいデータについて1時間毎にファイルを作るつもりで設定していると、毎時10分にならないと最終的な出力は得られないということになる。

なお「time_slice_formatで指定される時間幅の終端」というのは、具体的には以下のようになる。

  • %Y だけ指定した場合、年末
  • 中略
  • %Y%m%d%H だと1時間の終わり、つまり毎時59分59秒

ただし TimeSlicedOutput なプラグインで flush_interval を指定した場合は time_slice_format および time_slice_wait の影響が無視される挙動になる。ので以下。

  • バッファチャンクのサイズが buffer_chunk_limit に達した場合
  • バッファチャンクが作られてから flush_interval で指定した時間が経過した場合

また表にも入れたが fluentd 終了時の挙動として buffer_type file の場合にはflushされないが buffer_type memory の場合はflushされるという違いもある。このため memory のプラグインもシャットダウン時にいきなりデータロストするわけではない、が、出力処理が失敗した場合はバッファチャンク内のデータは失われる。逆に buffer_type file の場合はバッファチャンクファイルのまま残ることとなり flush されないので、これはこれで戸惑うことがあるかもしれない。

ところで拙作 fluent-plulgin-file-alternative や fluent-plugin-file-webhdfs などの PlainTextFormatterMixin を使った出力プラグインでは time_slice_format を個別に指定する必要はなく path から自動的に時刻プレースホルダを拾って time_slice_format を生成する。たいへん便利*2

プラグインでのデフォルト設定の上書き

たとえば out_exec_filter はBufferedOutputを継承しているが flush_interval を 1s で上書きしている。
また拙作 out_webhdfs はTimeSlicedOutputを継承しているが buffer_type のデフォルトは memory で上書きしている。

このような罠が世の中にはあるので注意が必要である。

buffer_path の話

out_file や out_file_alternative はローカルディスクへの書き込みを行うプラグインであり、バッファもデフォルトの buffer_type file のままであれば書き込み先ファイルと同じディレクトリに少し違うファイル名で書かれる。このパスは設定内の path パラメータから適当に生成される。
ただし、この便利機能は個別のプラグイン(たとえば out_file)内で実装されているもので FileBuffer や BufferedOutput/TimeSlicedOutput などの機能として実装されているわけではない。ので、各々のプラグインで buffer_type file を使う(あるいは TimeSlicedOutput を継承したプラグインを使う)ときには注意が必要である。

たとえば out_webhdfs は書き込み先 path が分散ファイルシステム上のものとなるため、ローカルパスの適当なところを指定できない。デフォルトでは buffer_type memory なので気にはならないが、自分で buffer_type file を指定する場合には buffer_path も指定しなければならない。*3

See Also

out_forward 特有の事情や round-robin などの話をまじえたエントリは過去に書いてた。
Fluentd out_forward における最適化パラメータいくつかの話 - tagomorisのメモ置き場

まとめ

以上のようなことを全て把握しなくてもなんとなく使っていればなんとなく使えるので、たぶん問題は起きない。

*1:おそらくファイルやDBやその他のものにデータを書き出すプラグインのほとんど全て

*2:個別に指定してもいいけど

*3:まで書いて同じく TimeSlicedOutput なプラグイン out_exec を読んでみたら tmpfile 使ってどうにかしてるなあ。こう直してもいいなー。デフォルトは memory のままでいいと思うんだけど。