sisoshima
2015年7月14日 16時39分
お世話になっております。五十島と申します。
Armadillo-IoTからTreasure Dataにログデータを格納する際に、fluentdを使用しています。
fluentdのメモリ使用量がいつの間にか肥大化しており、他プログラムを実行すると
「Cannot allocate memory」というエラーが出て、実行したプログラムが異常終了します。
fluentdのメモリ使用量を減らすことはできるでしょか。
fluentdの設定は下記記事を参考に行いました。
https://users.atmark-techno.com/blog/46/1219
/etc/config/fluent.confに次のように記述しています。
<source> type tail format json path /etc/config/fluent/fluent-log pos_file /etc/config/fluent/tail.pos tag td.db_name.table_name </source> <match td.*.*> type tdlog apikey *********** buffer_type memory flush_interval 60s use_ssl true </match>
以上、よろしくお願いします。
コメント
sisoshima
返信ありがとうございます。
psコマンドで確認してみましたが、複数起動させていないと思います。
プロセスは2つ動いていて、片方のメモリの使用量が増えていくような動きをしております。
[guest@armadillo-iotg (pts/0) ~]$ ps -o pid,rss,args | grep -e fluentd -e PID PID RSS COMMAND 1145 10m ruby /usr/bin/fluentd -d /var/run/fluentd.pid -c /etc/config/fluent.conf 6083 33m ruby /usr/bin/fluentd -d /var/run/fluentd.pid -c /etc/config/fluent.conf
よろしくお願いします。
at_ohsawa
大澤です。
tdlog pluginの flush_intervalを 1s程度の小さい値にしてみてください。
tdlog pluginは buffer plugin で実装されているので、
flush_interval の期間内は buffer_chunk_limit * buffer_queue_limit
(=512MB: デフォルト値) までデータをバッファしてしまいます。
他のbuffer plugin実装なプラグインを使う場合についても、
同様にflush intervalを小さく取る必要があります。
また、buffer plugin以外の要因では、rubyのgcが走る閾値がデフォルト
だと高すぎるので、fluentdを実行するシェルの環境変数に、下記の値を
exportして試してみてください。
export RUBY_GC_MALLOC_LIMIT=2000000 export RUBY_GC_MALLOC_LIMIT_MAX=8000000
この値でユースケースに合うか分らないのですが、
GCが走りすぎて遅い等の問題が無ければ、そのまま使えると思います。
RUBY_GC_MALLOC_LIMIT_MAXはの目安はfluentdを起動した直後の
メモリのfreeより少ない値にしてください。
Armadillo-IoTの標準イメージだと起動直後で32MB程度freeで
fluentdを起動するだけで 19MB feeeまで消費されるので、
RUBY_GC_MALLOC_LIMIT_MAX は多くても 15MB (15 * 1024 * 1024)
くらいでしょうか。
sisoshima
ご返信ありがとうございます。
設定を変更してみたのですが、fluentdの子プロセスが実行直後で22MBで、
数分後には40MB以上メモリを消費するようになりました。
RUBY_GC_MALLOC_LIMIT_MAXを3000000と極端に小さな値にしてみたら、
18MBぐらいで最初は抑えられていましたが、最終的には40MB以上になりました。
色々と試してみて気づいたのですが、初期起動時は親子プロセス合わせて28MB程度しか使われないようです。
ただし、ネットワークの不具合で転送できなかったり、tailで読み込むものがなくなると増加していくようです。
これは、GCがうまく動作していないのか、fluentdがそもそもメモリ消費量を気にしない作りなのか。
もし、何かわかればご助言いただけると幸いです。
fluent-bitという軽量版があるようなので、そちらも検討しています。
at_yashi
> 色々と試してみて気づいたのですが、初期起動時は親子プロセス合わせて28MB程度しか使われないようです。
> ただし、ネットワークの不具合で転送できなかったり、
ネットワークの不具合がある場合、TreasureDataLogOutput は、BufferedOutput なので
メモリ使用量はある一定量(buffer_queue_limit)まで増え続けます。このメモリは、
必要なデータがはいっているバッファなので、いくらGCが動いても消せません。
fluentd的には、ネットワーク障害があってもデータをロストしないことを
売りにしている(はずな)ので、このような作りだと理解しています。
http://docs.fluentd.org/articles/buffer-plugin-overview
> tailで読み込むものがなくなると増加していくようです。
こっちは、なんでしょうね....。
sisoshima
ありがとうございます。段々と理解してきました。
> メモリ使用量はある一定量(buffer_queue_limit)まで増え続けます。このメモリは、
> 必要なデータがはいっているバッファなので、いくらGCが動いても消せません。
つまりは、一回メモリをある量まで確保してしまった場合、
fluentdを終了させるまで確保され続けるという理解でいいんですよね。
(送信データの有無関係なく)
buffer_chunk_limit と buffer_queue_limitのサイズを小さくすれば、使用量は抑えられるけど、
遅延などが発生してqueueに収まらない量になった場合にデータが欠落してしまうんですね。
だとすると、in_tailでレコードが追加されたら読み込むよりも、一定期間たったら読み込む等、
input側で制御すると多少はfluentdが占有してしまうメモリ量を減らせるかもしれないですね。
詳しい説明ありがとうございます。
at_yashi
> > メモリ使用量はある一定量(buffer_queue_limit)まで増え続けます。このメモリは、
> > 必要なデータがはいっているバッファなので、いくらGCが動いても消せません。
>
> つまりは、一回メモリをある量まで確保してしまった場合、
> fluentdを終了させるまで確保され続けるという理解でいいんですよね。
> (送信データの有無関係なく)
勘違いさせてごめんなさい。「いくらGCが動いても、『送信されていないデータが
入っているメモリー (chunk) は』消せません。」です。一度送信されてしまえばメモリーは、
Queueから外されて、GCに回収されます。コードでいうと
buffer.rb::pop() -> buffer.rb::write_chunk() -> out_tdlog.rb::write()
という流れで、chunkが TDに uploadされます。
pop()のスコープでは次に、delete_if() で今 upload した chunk を @queue から消します。
これで、upload した chunk へのリファレンスが消えるはずなので、次の GCのタイミングで
メモリが開放されます。(ruby 2.1 からは generation gc なので、chunk の世代が進んでいたら
旧世代の sweep でしか消されませんが、概念的には次です)
> buffer_chunk_limit と buffer_queue_limitのサイズを小さくすれば、使用量は抑えられるけど、
> 遅延などが発生してqueueに収まらない量になった場合にデータが欠落してしまうんですね。
ですね。
> だとすると、in_tailでレコードが追加されたら読み込むよりも、一定期間たったら読み込む等、
> input側で制御すると多少はfluentdが占有してしまうメモリ量を減らせるかもしれないですね。
fluentd は、基本的に in 側のタイミングで処理がスタートするアーキテクチャです。TailInputは
1秒固定ですが NewTailInput の場合は refresh_interval で時間をコントロールできます。
bufferedの場合は、out 側で thread をつくるので in側とは独立で動作します。
in側のタイミングをあまり気にしないのであれば、今の tdの plugin のように buffered outputからの
派生ではなく、output からの派生の方がストレートですね。ただネットワークの遅延が
そのまま fluentd の eventloop に影響を及ぼすので、そっちはそっちで考えることがありそうです。
ただ、内部 buffer にデーターが貯まることはないはずです。
fluent-bit の初期のコードは、bufferedoutput というより non-buffered な outputの実装になっていました。
at_takashi.sasayama
2015年7月15日 16時12分
笹山です。
> Armadillo-IoTからTreasure Dataにログデータを格納する際に、fluentdを使用しています。
> fluentdのメモリ使用量がいつの間にか肥大化しており、他プログラムを実行すると
> 「Cannot allocate memory」というエラーが出て、実行したプログラムが異常終了します。
fluentd が複数起動していることは無いでしょうか?
過去に、誤って fluentd を複数起動してしまった結果、似た問題が発生した事例がありました。
同じ問題かもしれませんので、ご確認いただければと思います。