Java 版 Fluentd サーバである、Influent のベンチマークを取ってみました。今回は第一弾で、今後も性能を改善しながら、都度ベンチマーク結果を載せていく予定です。
テスト概要
fluentd-benchmark を用いて Fluentd 及び Influent へ負荷をかけます。これは dummer で生成したイベントを Fluentd エージェントで大量に送りつけるもので、fluent organization のものをほぼそのまま用いています。
受信サーバの処理は、受信したイベントの数を1秒ごとに標準出力に書き出すという単純なものです。Fluentd のテストには上記の fluentd-benchmark に同梱されている設定を用います。Influent のテストには同じような処理を行うこちらのアプリケーションを用います。
Disclaimer
Fluentd と Influent の比較について
この記事は Fluentd のベンチマーク結果を Influent のベンチマーク結果に併記しています。ただし、この結果をもとにどちらの性能が優れているかを推し量ることはできない、という点に留意してください。
Influent は Fluentd が持つ機能のいくつか、例えばルーティング機能のようなものを提供していません。そのため、直接比較すると Fluentd に不利な結果となるでしょう。また次に述べるように Fluentd の性能を引き出しきれている保証もありません。
Fluentd のベンチマーク結果について
本記事に記載している Fluentd のベンチマーク結果は、本来の性能を発揮できていない可能性があります。理由は、私が Fluentd や Ruby のパフォーマンスを引き出す術に明るくないからです。
サーバのセットアップ方法やベンチマークの実行方法は influent-benchmark により管理されているので、よりよいテスト方法をご存じの方は PR してくれると嬉しいです。
テスト環境
サーバ
送信サーバ及び受信サーバには、Google Compute Engine asia-northeast1 リージョンの n1-highcpu-32 を用いました。
送信サーバ一台だと負荷をかけきれないケースがあるので、送信側は二台用意しました。それぞれ20プロセスの Fluentd が並列にイベントを送信します。
バージョン
環境構築は influent-benchmark の 78828a54a18783f5b976935e3df33aa709164a6d で行いました。
Fluentd のバージョンは 0.12.31 で、Influent のコミット ID は f38aa35ca708a72df66f07b5e87a43a0b24eb3ef です。
プロトコル
Fluentd 0.12 を用いて、at-most-once(require_ack_response なし)プロトコルでイベントを送信しました。at-least-once でも軽く試しましたが、Fluentd がそれなりの数のイベントをバッファリングしつつ送っているからか、あまり結果は変わりませんでした。
テスト結果
ある程度負荷をかけて安定したタイミングで、受信していたイベント数をアバウトに記録しました。また今回は CPU がボトルネックとなっていたので、CPU 使用率も載せています。
Influent のアプリケーションのうち、すごくアクティブなスレッドは1スレッドのみです。CPU 使用率が100%を超えている分はほぼ GC スレッドによる処理であると思われます。
Fluentd | Influent | ||||
---|---|---|---|---|---|
送信イベント数(秒) | 受信イベント数(秒) | CPU (%) | 受信イベント数(秒) | CPU (%) | 備考 |
400000 | 400000 | 40~45% | 400000 | 30~45% | |
600000 | 600000 | 60~65% | 600000 | 40~55% | |
800000 | 800000 | 80~90% | 800000 | 60~70% | |
1000000 | 800000~1000000 | 100% | 1000000 | 70~90% | |
1200000 | 800000~950000 | 100% | 1200000 | 85~100% | |
1400000 | N/A | N/A | 1400000 | 100~115% | |
1600000 | N/A | N/A | 1600000 | 125~145% | |
1800000 | N/A | N/A | 1800000 | 95~155% | テスト中に JVM のヒープサイズ拡張 |
2000000 | N/A | N/A | 2000000 | 100~115% | |
2200000 | N/A | N/A | 2000000~2150000 | 110~115% | |
2400000 | N/A | N/A | 2000000~2150000 | 110~115% |
雑感
『Java で Fluentd の in_forward っぽいことをするライブラリを作りました』で予想していたとおり、シンプルな処理では大きな差が出ませんでした。プロファイリング結果によると、PackedForward の MessagePackEventStream をパーズする処理でかなりの CPU を使ってしまっているので、性能が劇的に改善することもなさそうな感じがしています。
とはいえ Influent は性能面の最適化をほとんどしていないので、後述する TODO を解決して、またベンチマークを取っていこうと思います。
TODO
MessagePack デコード処理の改善
msgpack-java はインクリメンタルなデコードができないので、パケットを受け取る度に毎回一から unpack しています。この部分がそこそこプロファイリング結果に出てきていたので、ストリームデシリアライザを実装しようと思っています。
マルチスレッド対応
現状 Influent のネットワーク処理〜MessagePack のデコード処理部分はシングルスレッドで動いています。一方ユーザーの処理(受け取ったイベントをどこかに送信するとか)はマルチスレッドで処理できるようになっています。この構成だと 10Gbps の線の上で、Influent がボトルネックとなってしまうことがほぼ確定しています。
次のバージョンの Fluentd にはポートを複数ワーカーで共有する機能(Symmetric multi process)が入るらしいので、Influent にも MessagePack のデコードをスケールする仕組みを導入したいです。
0.14 を使ったテスト
現在リリースされている Fluentd 0.14 はタグの送信フォーマットが仕様に沿っておらず、Influent で受け取れないので今回は 0.12 のみを使ったテストとなりました。Fluentd 0.14 自体の性能にも関心があるので、特に Symmetric multi process 機能が入ったらまた比較してみたいです。
より現実的なテストケース作成
Fluentd 本体がよくできている以上、Java の性能を活かせるのは、やはり重い計算を行う場合や、マルチスレッド処理、IO を伴う処理が必要な場合ではないかと考えています。fluentd-benchmark は若干シンプルよりなので、Google Cloud Pub/Sub に書き込むとか、そういうケースも試験できたらいいなと考えています。