読者です 読者をやめる 読者になる 読者になる

たごもりすメモ

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

out_exec_filter 入出力フォーマットの変更による負荷の変化

fluent

まず前置きですが、みんな大好きFluentdがなぜ*1実用上充分なくらい高速に動作するかというとそれは内部のシリアライズ/デシリアライズフォーマットとして使われているMessagePackのおかげによるところが大きいわけですね。

ところで Fluentd の組込みプラグインのひとつに out_exec_filter というのがありまして、これは任意のプログラムを子プロセスとして実行し、そのSTDIN/STDOUTにFluentdのメッセージを通すことでどんな処理でも記述可能なフィルタとして使いましょう、というやつ。
これは当初はTSVしかサポートしてなかった*2んだが、対応フォーマットがいくつか増えていまではjsonとかmsgpackでも入出力可能になっている。もちろん外部プログラムの側でもjsonやmsgpackを読み書きするように書かれてないといけない。

さてお仕事でこの exec_filter をがっつり使っていて、いまやこいつを8プロセス動かしているサーバが10台ある。馬鹿にならない台数なので負荷が減って台数を減らせればたいへん嬉しい。負荷としては外部のフィルタプログラムと同じくらい入出力のブリッジになっているfluentdプロセスもCPUを食ってる。こいつがもうちょっと軽くならないかなあ、と思ってた。

ので、TSVでやってた処理をmsgpackでも入出力できるようフィルタプログラムのコードを改造し out_exec_filter は子プロセスへの入出力をmsgpackでやれるようにしてみた。その上でどのくらい負荷が違うのかベンチマークをとってみたのが以下のグラフ。最初の30分の山がTSVで走行したもの、次の1時間がmsgpackに変えて走行したもの。
負荷はだいぶがっつりかけた。詳細は以下のとおり。

  • サーバ:
  • ソフトウェア
  • 負荷
    • 同スペックの別サーバに立てた fluentd out_forward から上記8プロセスに対してラウンドロビン
    • Maxで 300msg/send * 15 send/sec のメッセージを送るプロセスを10プロセス起動




変わってねえ! まるで変わらん! どっちも処理のスループットは 25000 msg/sec くらいがmaxで負荷に対して追い付いておらず、ちょっと遅延が出た。にしてもmsgpackにしてもぜんぜん速くなってねえ!

topでなんとなーく見てる限りだと、fluentdプロセスの cpu usage が少し下がって、かわりに perl プロセスの cpu usage が上がり、合計としては前と変わらず、みたいに見える。これはまあ印象論に近いあたり。

メモリについては msgpack を使ったときはたぶんメモリ空間のフラグメンテーションか何かが進行してる。ベンチ終わったあとも memory used が5GB以上あるのはそのせい。msgpack v0.5 はやく使いたいなあ。

考察

exec_filter がmsgpack入出力できるといっても子プロセスに渡す前/渡した後に time/tag の処理が必要なため、chunkのmsgpackバイナリをそのまま子プロセスのパイプに書き込めるわけではない。かならずunpack/packが入る。このため期待したほどには速くなかったのかなー、と思う。*3

となるとあとはTSVとMessagePackとの比較ということになる。fluentd 側で cpu usage が下がったとすれば msgpack の力なのだろう、おそらく。
perl 側で負荷が上がったとすれば考えられることはいくつか。
TSVは行単位での入出力なので perl のI/Oバッファリングが最大限に効くが msgpack は行単位での処理が不可能なので、自分で nonblock I/O をがんばりつつ streaming unpack しなければいけない。これは効率悪いかも。またタブ区切りの処理はperlであればmsgpackと勝負できるくらい充分に速い、というのもまあ考えられる。
最後に、msgpackだとフィールド名がデータ中に含まれるため、レコードのフィールド数がそれなりに多い場合にはI/Oバイト数がTSVに較べてそれなりに増加することが考えられる。これが性能を直撃したおそれは否定できない。

ということで、まあよく考えてみればそんな高速化するばかりだったかというと、そうでもない理由もありましたね。ということがわかる結果でした。まる。

*1:ruby + TCPという従来の感覚だと「遅そう」な組合せを使っているにもかかわらず

*2:よね、確か

*3:ちょっとコードを眺めてみたが、あんまり高速化の余地もなさそうだった、ざんねん