Kafka

Apache Kafkaの性能検証(5): システム全体のレイテンシについて

初版: 2018/11/16

著者: 伊藤 雅博, 株式会社日立製作所


はじめに

この投稿ではオープンソースカンファレンス2017.Enterpriseで発表した「めざせ!Kafkaマスター ~Apache Kafkaで最高の性能を出すには~」の検証時に調査した内容を紹介します(全8回の予定)。本投稿の内容は2017年6月にリリースされたKafka 0.11.0 時点のものです。

最終回となる今回は、システム全体のレイテンシについて紹介します。前回まではデータ処理のスループットに着目してチューニングを行ってきました。一般的に、スループットが増加するとレイテンシも増加しますが、これまでの検証で行ったチューニングではレイテンシを考慮していませんでした。そこで今回はレイテンシの測定結果について紹介します。

過去の投稿:

1. Apache Kafkaの概要とアーキテクチャ

2. Apache KafkaのProducer/Broker/Consumerのしくみと設定一覧

3. Apache Kafkaの推奨システム構成と性能の見積もり方法

4. Apache Kafkaの性能検証(1):検証内容と検証環境について

5. Apache Kafkaの性能検証(2):Producerのチューニング

6. Apache Kafkaの性能検証(3):Brokerのチューニング結果

7. Apache Kafkaの性能検証(4):Producerの再チューニングおよびConsumerのチューニング結果


システム全体のレイテンシ

システム全体のレイテンシは、ProducerのSend APIでRecordを追加する時点から、ConsumerのPoll APIでRecordを取得するまでの時間です。このレイテンシは以下に示す5つの処理時間の合計値となります。

kafka08_01.png

前回までのチューニングを行った状態で、上記の各処理のレイテンシを測定した結果を以下に示します。これらのレイテンシは、これまで測定してきたスループットと同様に、KafkaがJMXで公開しているメトリックを収集したものです。

① Send APIのブロック時間

ユーザスレッドがSend APIでRecordを追加するスループットが、Producerのリクエスト送信スループットよりも高い場合は、Producerのバッファがいずれ満杯となります。Producerのバッファが満杯になると、ユーザスレッドはバッファに空きが出るまでSend APIでブロックされます。

今回の検証で使用した40個のProducerについて、Producerごとの空きバッファサイズの推移を以下に示します。測定開始直後から空きバッファサイズは減少し続け、2分ほど経過した時点でバッファの空き容量がほぼ0になることが分かります。そのため、2分ほど経過した時点からSend APIでブロックが発生していたと考えられます。

kafka08_02.png

Producerの秒間リクエスト送信数の推移を以下に示します。測定開始から10秒ほど経過した後は、1Producerの秒間送信リクエスト数は3程度で推移していることが分かります。

kafka08_03.png

今回の検証ではSend APIのブロック時間を測定していませんが、リクエストが送信されればバッファが空くため、ブロック時間は1秒÷3リクエスト≒333ミリ秒程度と推定できます。

② Producerのバッファリング時間

Send APIでRecord Batchに追加されたRecordは、ネットワークスレッドがリクエストとして送信するまで、Producerのバッファに留まり続けます。Recordのバッファリング時間の推移を以下に示します。測定開始直後からバッファリング時間は徐々に増加していき、2-3分経過した後は50秒程度で推移していることが分かります。

kafka08_04.png

今回の検証では、40個のProducerによる送信スループットの合計が803MB/sだったので、1 Producerあたりの送信スループットは約20MB/sとなります。今回の検証ではProducerの buffer.memory を 1GB に設定したため、バッファが満杯になるまでRecordが溜まると、Recordは送信されるまでに 1GB ÷ 20MB/s ≒ 50秒 かかることになります。

③ Produceリクエストのレイテンシ

今回の検証はProduceリクエストの acks を all 、Topicの min.insync.replicas を 2 に設定したため、ProduceしたRecordが2個以上のReplicaに複製された時点でレスポンスが返されます。この複製が完了したRecordは、Consumerから取得できるようになります。Produceリクエストのレイテンシの推移を以下に示します。スパイク時はレイテンシが10秒を超えることもありますが、平均すると2.5秒程度で推移していることが分かります。

kafka08_05.png

④ Fetchリクエストのレイテンシ

今回の検証では6個のConsumerでConsumer Groupを構成して、TopicのデータをFetchし続けました。各Consumerが送信したFetchリクエストのレイテンシの推移を以下に示します。レイテンシは 100ミリ秒から 300ミリ秒の間でばらつきがありますが、平均すると150ミリ秒程度で推移していることが分かります。

kafka08_06.png

⑤ Poll APIのレイテンシ

Consumerを使用するユーザアプリケーションは、Poll APIを呼び出してRecordを取得します。このときConsumerがRecordを保持していればRecordが即時返却されますが、保持していない場合は新たなRecordが得られるまでブロックされます。

今回の検証ではPoll APIのレイテンシを測定していませんが、Consumeスループットは803MB/s程度で推移していました。そのためRecordは即時返却され続けたと考えられ、レイテンシは数ミリ秒程度と推定できます。


レイテンシについての考察

上記の①から⑤のレイテンシを合計すると53秒程度でした。今回は検証ではスループットを最大化するために、Producerの送信能力を超える速さでRecordを追加したので、Producerのバッファが詰まって送信まで50秒もかかっていました。Producerの buffer.memory を増やすと、ユーザアプリケーション側から流れてくるRecord流量の一時的な増加には耐えやすくなります。しかしバッファリング時間を監視していないと、Recordの送信が遅れていることに気付けないというリスクもあります。

Kafkaの最大スループット(803MB/s)を超えない範囲のRecord流量であれば、Producerで詰まることはなくなる(①、②の待ち時間ほぼ無くなる)ため、レイテンシは3秒程度になると推定できます。ただしRecord Batchの蓄積が遅くなるため、linger.msを増やす必要があるかもしれません。


おわりに

ここまで、Kafkaの調査内容と性能検証結果を8回に分けて紹介してきました。Kafkaはスケーラビリティに優れた分散メッセージキューです。しかし、データを保護するために同期レプリケーションを行いつつ性能を引き出すには、内部構造を理解した上で適切なチューニングが必要となります。