大規模なトラフィックが発生した際、Kafkaのメッセージ処理が追いつかず、ダウンストリームのデータに数分から数時間の遅延が生じるケースがあります。この遅延(ラグ)を放置すると、リアルタイム分析の精度が低下し、システム全体の信頼性が損なわれます。
この記事では、Prometheusを用いたコンシューマーラグの可視化と、リバランスによる停止時間を最小限に抑えながらパーティションをスケールアウトする実戦的な手法を解説します。
TL;DR — Kafkaのコンシューマーラグは「プロデューサーのオフセット」と「コンシューマーのオフセット」の差分であり、監視にはKafka Lag Exporterが最適です。処理能力の限界時には、パーティション追加とコンシューマー増設を同期させてスケールアウトします。
1. Kafkaコンシューマーラグの本質
💡 イメージで理解する: 人気ラーメン店の行列を想像してください。店員(コンシューマー)がラーメンを作る速度よりも、客(メッセージ)が並ぶ速度が速い場合、行列(ラグ)は伸び続けます。行列を解消するには、調理台(パーティション)を増やし、店員を増員する必要があります。
Kafkaにおけるコンシューマーラグ(Consumer Lag)とは、トピックに書き込まれた最新のオフセット(Log End Offset)と、コンシューマーグループが最後にコミットしたオフセット(Current Offset)の物理的な差分を指します。最新バージョン 3.7.x 以降でも、このメトリクスはシステムの健全性を測る最も重要な指標です。
従来のJMXメトリクスのみの監視では、コンシューマーが停止している場合にラグを正確に計算できない問題がありました。現在は kafka-lag-exporter などの外部エージェントを使い、クラスター全体から客観的にラグを算出する手法が標準的です。
2. ラグ急増が発生する主なシナリオ
プロモーションイベントや突然のスパイクにより、入力トラフィックが予想を上回った際に発生します。1秒あたりのメッセージ数がコンシューマーの最大スループットを超えると、ラグは線形に増加します。
特定のパーティションにデータが偏る「データスキュー」が発生している場合も危険です。全体の処理能力には余裕があっても、特定のコンシューマーだけが過負荷になり、パイプライン全体に遅延を波及させます。また、DB書き込み待ちなどの外部I/Oブロッキングが原因でコンシューマーの処理速度が低下する場合も、ラグが急増する典型的なケースです。
3. Prometheusによる監視とスケールアウトの実装
監視環境の構築からパーティション拡張の手順を段階的に説明します。
ステップ 1. Kafka Lag Exporterの配置
JMXエージェントに依存せず、Prometheus形式でメトリクスを公開するために kafka-lag-exporter をデプロイします。
# helm chartでのインストール例
helm install kafka-lag-exporter kafka-lag-exporter/kafka-lag-exporter \
--set clusters[0].name=main-cluster \
--set clusters[0].bootstrapServers=kafka:9092
ステップ 2. Prometheusアラートの設定
ラグの絶対値だけでなく、ラグの解消予想時間(Time-to-Full-Consume)を基準にアラートを設計します。
# prometheus-rules.yaml
groups:
- name: KafkaAlerts
rules:
- alert: HighConsumerLag
expr: kafka_consumergroup_group_max_lag_seconds > 300
for: 5m
labels:
severity: critical
annotations:
description: "Consumer group lag is over 5 minutes for 5m."
ステップ 3. パーティションとコンシューマーの拡張
処理能力を向上させるために、トピックのパーティション数を増やし、コンシューマーインスタンスを同数まで増設します。
# パーティションを10から20へ増加
kafka-topics.sh --bootstrap-server kafka:9092 \
--alter --topic orders-topic --partitions 20
4. 静的拡張 vs 動的自動スケール
スケーリング戦略を選択するための比較です。
| 比較基準 | 静的パーティション設計 | HPAによる動的スケール |
|---|---|---|
| 管理の容易さ | 高い(固定設定) | 低い(設定が複雑) |
| コスト効率 | 低い(常時最大確保) | 高い(必要時のみ) |
| リバランス頻度 | 低い | 高い |
| 適したユースケース | 予測可能なトラフィック | 急激なスパイクが多い環境 |
トラフィックの予測が可能な場合は静的設計を、クラウドネイティブな環境でコストを最適化したい場合はKubernetesのHPA(Horizontal Pod Autoscaler)とKEDAを組み合わせた動的スケールを推奨します。
5. 注意事項
⚠️ よくあるミス: パーティション数は増やすことはできますが、減らすことはできません。過剰なパーティション追加は、メタデータの肥大化やブローカーのフェイルオーバー時間の増大を招きます。
パーティションを増やすと、メッセージのキーに基づく順序性が保証されなくなる点に注意が必要です。以前と同じキーのメッセージが異なるパーティションに割り当てられるため、状態を持つ処理を行っている場合はアプリケーション側での考慮が不可欠です。
エラー別の対処法
# Error: RebalanceInProgressException
# 原因: 頻繁なコンシューマー増減によるリバランスの嵐
# 解決策: session.timeout.ms の調整と、増設を段階的に行う
6. 実戦Tips
コンシューマーの処理速度を上げるために、max.poll.records を調整して1回のフェッチで取得する件数を最適化してください。デフォルト値ではI/O待ちが長い処理において効率が悪くなることがあります。また、fetch.min.bytes を増やすことで、ネットワークのオーバーヘッドを削減し、全体のスループットを約15%向上させることが可能です。
Confluentの調査によると、パーティション数はブローカーあたり4,000個以内に抑えることが推奨されています。無計画な拡張は避け、監視データに基づいた論理的なキャパシティプランニングを行ってください。
📌 まとめ
- コンシューマーラグは Prometheus + Kafka Lag Exporter で可視化する
- パーティション追加はコンシューマー増設とセットで実施する
- 順序性の欠如とリバランスコストを常に考慮する
よくある質問
Q. パーティションを増やすと順序はどうなりますか?
A. 追加後は同じキーのデータが別のパーティションに飛ぶため、順序は崩れます。
Q. ラグが減らない場合の最初のチェック項目は?
A. コンシューマーのCPU使用率と外部DBのレイテンシを確認してください。
Q. コンシューマー数はパーティション数より多くできますか?
A. できません。余ったコンシューマーはアイドル状態になりリソースの無駄です。
Post a Comment