Fluent Loggerの信頼性を高めるには - 2017-04-28 - ククログ

ククログ

株式会社クリアコード > ククログ > Fluent Loggerの信頼性を高めるには

Fluent Loggerの信頼性を高めるには

はじめに

Fluentdにログを送る方法として、Fluent Loggerを使う方法があります。 RubyやJavaにはそれぞれfluent-logger-rubyやfluent-logger-javaなどのFluent Loggerがあり、よくメンテナンスされています。 この記事ではFluent Loggerを使ってFluentd v0.12またはv0.14にログを送信する時にどのようにするとより確実にログ転送ができるようになるかを解説します。

最小構成のFluent_Loggerを作成するには では最小構成のFluent Loggerはどのような仕様に基づき実装されるべきかを解説しました。この記事はその続編です。

確実にログを送るには

確実にログを送るにはエラーが起きた時にそのエラーを回復する手段を提供されていることが必要です。

ログが送れたことをFluent Logger側で検出する

より確実にログを送信したことをLogger側で確認するにはOptionやResponse節にあるようにoptionを使う事が重要になります。 optionの中に128bitユニークなIDのbase64を取ったものをchunkをキーとしたペアに入れ、ackで返って来たbase64の値と比較してやる事で、Logger側で確実に送信されたものと判定出来ます。 1 確実に送信されたログに関してはバッファから削除してしまって問題ありません。

TCP接続のエラーから回復して何度か再試行する

また、ネットワークの状況によっては、一回でTCPの接続を確立するのが難しく、何回か再試行する必要があることがあります。 このときに、接続を複数回繰り返す方法としては、一定期間ごとに試行する方法(periodic)、試行間隔を指数関数的に増やして行く方法(exponential back-off)のどちらかが取られます。

送信の再試行回数を超えてエラーとなった時のログ消失を防ぐ方法

アプリケーションが予期しない理由により停止してしまった場合に備えて、送信していないログをメモリ上のバッファに溜めておくだけでなく、ファイルに書き込む必要がある場合もあります。 このとき、ファイルにバッファを書き込む際にはFluentdのプラグインで扱いやすい形にしておくほうがよいです。 例えば、msgpackのバイナリ列のバッファをそのまま吐き出したり、TSV形式にすることで、in_tailにより送信ができなかったファイルを後から送信する、という回復処理が行えるようになっているとFluentdに長期間繋がらなかった際にログの消失を抑える有効な手立てとなります。

Fluent Loggerのよくある実装を踏まえての解説

ここからはFluent Loggerのよくある実装を踏まえて解説を行います。 これら3つの仕様をFluent Loggerに入れることができればより強固にFluentdへログを転送することが可能になるでしょう。

Require Ack Response

確実にログを送ったことをFluent Logger側で検出するのに実装するべきことは次の通りです。 Fluent protocolでは最後のoptionというフィールドに12byteのbase64エンコードされた値をchunkをキーとするKey-Valueを持たせることができます。2 このオプションを用いることで、Fluentdへのログ送信が完了したことがFluent Logger側で確認できるようになります。

このオプションが実装されているFluent LoggerにはFluencyfluent-logger-nodeがあります。

送信の再試行

TCP接続のエラーから回復して何度か再試行する、ということを実現するには再試行の戦略を決める必要があります。 大きく分けてTCP接続に失敗した時に等間隔で再試行するか、それとも再試行の間隔を指数関数的に増やしていくかの二つの方法が取れます。 等間隔で再試行を行う場合は再試行の時間まであとどれくらいかを予測しやすくなりますが、一方で送信先のノードが落ちている場合は再試行回数が極端に増える結果となります。 そのため、最初は再試行間隔が最初は徐々に増やされ、だんだんと間隔が開いていく指数関数的に再試行時間を決める方法を筆者はとることが多いです。

送信がうまくいかなかった時のファイルへの出力

送信の再試行回数を超えてエラーとなった時のログ消失を防ぐにはどうしてもログが送信できない場合に、ローカルのストレージへファイルとして出力する方法が取れます。in_tailではmsgpackやTSV形式などでログファイルをパースすることが可能です。 どうしてもエラーの回復ができない場合には最終的にはFluent Loggerに渡したログをファイルに出力し、後日改めてFluentdのin_tailなどで送信エラーの起きたログを回収するようにすると良いでしょう。

おわりに

Fluent Loggerは単純にログを転送するだけではなく、Logger側でログがFluentdへ転送できたことを検知する仕組みを入れることができたり、TCP接続を確実に確立するための再試行の機構を取り入れたり、再試行回数の上限を超えてしまった時はファイルに転送しようとしたログをダンプする戦略が取れることを解説しました。 なお、この記事では解説できませんでしたが、この記事は筆者が作成したRustのFluent Loggerのfruentlyを作成するにあたって得られた知見を元にしています。

  1. より詳細には https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#option を参照すること。

  2. https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#grammar