多段fluentd + mongodb のハマリ所

fluentdを多段構成にして、mongodbに出力するところでハマったのでメモ。

上の構成のように、各サーバにfluentd + out_forwardを置き、集約するログサーバにfluentd + out_mongoでmongodbに出力している場合に、上段のfluentdでbuffer_chunk_limitを10mより大きい値にしていると、エラーになることがあります。

まず、out_mongoでbuffer_chunk_limitを10m以内にしないといけない理由は、fluentdからMongoDBへ連携する際の注意点 #fluentdを参考にしてください。

ここで多段構成の場合、上流の buffer_chunk_limitが大きいと上流から大きなサイズのデータの塊が流れてくることがあります。それを受けとったfluentdはそれをそのままoutput pluginに流す実装となっているようです。そのため、末端のout_mongoだけ buffer_chunk_limit 10m としていても、上流から来たデータの塊をそのままmongodbにinsertしようとして、エラーとなるようです。

ちなみにこの場合のエラーメッセージとしては以下のようなものが出てきます。"next retry will be"といってますが、chunkが分割されるわけではないので、永遠に失敗し続けるわけです。

2013-02-22 13:46:56 +0900 [warn]: temporarily failed to flush the buffer, next retry will be at 2013-02-22 13:46:58 +0900. error="Exceded maximum insert size of 16,000,000 bytes" instance=260250280 time=1361508416

対策としては、末端にout_mongo (や、buffer_chunk_limit に制限を加える必要があるplugin)を使う場合、その上流の全てのfluentdでその上限値(out_mongoの場合 10m)に設定する必要がある、ということになりそうです。

設定を修正した後は、mongodbで8000lines/secぐらいまでの性能は確認できました。ちなみにこの時のIOPSが400〜500ぐらいだったので、IO性能はまだまだいけそう。前の記事でmongodbのinsert性能が低いような話を書きましたが、原因は別のところにあったので訂正します。

修正後の設定は以下のようになります。上流のfluentdのbuffer_chunk_limitもきっちり10mにしておきましょう!

  • 上流サーバ
<source>
  type tail
  format ltsv
  path /var/log/httpd/access_log.ltsv
  tag proxy.access_log
  pos_file /var/tmp/fluent.log.pos
</source>

<match **>
  type forward

  buffer_type memory
  # buffer_chunk_limit must be under 10m if out_mongo is used in downstream.
  buffer_chunk_limit 10m
  buffer_queue_limit 128
  flush_interval 1s
  retry_limit 10
  retry_wait 5s
  send_timeout 5s
  recover_wait 5s
  heartbeat_interval 1s
  phi_threshold 10
  hard_timeout 10s
  <server>
    host fluentd
    port 24224
  </server>
</match>
  • ログサーバ
<source>
  type forward
  port 24224
  bind 0.0.0.0
</source>

<match **>
  type mongo
  tag_mapped

  capped
  capped_size 10m

  nodes mongod
  database fluent
  collection debug

  buffer_type memory
  buffer_chunk_limit 10m
  buffer_queue_limit 1280
  flush_interval 1s
  retry_limit 10
  retry_wait 5s
</match>