初版: 2018/11/16
著者: 伊藤 雅博, 株式会社日立製作所
はじめに
この投稿ではオープンソースカンファレンス2017.Enterpriseで発表した「めざせ!Kafkaマスター ~Apache Kafkaで最高の性能を出すには~」の検証時に調査した内容を紹介します(全8回の予定)。本投稿の内容は2017年6月にリリースされたKafka 0.11.0 時点のものです。
最終回となる今回は、システム全体のレイテンシについて紹介します。前回まではデータ処理のスループットに着目してチューニングを行ってきました。一般的に、スループットが増加するとレイテンシも増加しますが、これまでの検証で行ったチューニングではレイテンシを考慮していませんでした。そこで今回はレイテンシの測定結果について紹介します。
過去の投稿:
- Apache Kafkaの概要とアーキテクチャ
- Apache KafkaのProducer/Broker/Consumerのしくみと設定一覧
- Apache Kafkaの推奨システム構成と性能の見積もり方法
- Apache Kafkaの性能検証(1):検証内容と検証環境について
- Apache Kafkaの性能検証(2):Producerのチューニング
- Apache Kafkaの性能検証(3):Brokerのチューニング結果
- Apache Kafkaの性能検証(4):Producerの再チューニングおよびConsumerのチューニング結果
システム全体のレイテンシ
システム全体のレイテンシは、ProducerのSend APIでRecordを追加する時点から、ConsumerのPoll APIでRecordを取得するまでの時間です。このレイテンシは以下に示す5つの処理時間の合計値となります。
前回までのチューニングを行った状態で、上記の各処理のレイテンシを測定した結果を以下に示します。これらのレイテンシは、これまで測定してきたスループットと同様に、KafkaがJMXで公開しているメトリックを収集したものです。
① Send APIのブロック時間
ユーザスレッドがSend APIでRecordを追加するスループットが、Producerのリクエスト送信スループットよりも高い場合は、Producerのバッファがいずれ満杯となります。Producerのバッファが満杯になると、ユーザスレッドはバッファに空きが出るまでSend APIでブロックされます。
今回の検証で使用した40個のProducerについて、Producerごとの空きバッファサイズの推移を以下に示します。測定開始直後から空きバッファサイズは減少し続け、2分ほど経過した時点でバッファの空き容量がほぼ0になることが分かります。そのため、2分ほど経過した時点からSend APIでブロックが発生していたと考えられます。
Producerの秒間リクエスト送信数の推移を以下に示します。測定開始から10秒ほど経過した後は、1Producerの秒間送信リクエスト数は3程度で推移していることが分かります。
今回の検証ではSend APIのブロック時間を測定していませんが、リクエストが送信されればバッファが空くため、ブロック時間は1秒÷3リクエスト≒333ミリ秒程度と推定できます。
② Producerのバッファリング時間
Send APIでRecord Batchに追加されたRecordは、ネットワークスレッドがリクエストとして送信するまで、Producerのバッファに留まり続けます。Recordのバッファリング時間の推移を以下に示します。測定開始直後からバッファリング時間は徐々に増加していき、2-3分経過した後は50秒程度で推移していることが分かります。
今回の検証では、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秒程度で推移していることが分かります。
④ Fetchリクエストのレイテンシ
今回の検証では6個のConsumerでConsumer Groupを構成して、TopicのデータをFetchし続けました。各Consumerが送信したFetchリクエストのレイテンシの推移を以下に示します。レイテンシは 100ミリ秒から 300ミリ秒の間でばらつきがありますが、平均すると150ミリ秒程度で推移していることが分かります。
⑤ 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はスケーラビリティに優れた分散メッセージキューです。しかし、データを保護するために同期レプリケーションを行いつつ性能を引き出すには、内部構造を理解した上で適切なチューニングが必要となります。