Kafka のコスト最適化は、パーティション数・圧縮・保持(retention/compaction)の三点を揃えることから始まります。過剰なパーティションはメモリ/FD/レプリケーション流量を押し上げ、圧縮のミスマッチはCPU過負荷やスループット劣化を招き、保持ポリシーの誤りはストレージ爆発を起こします。
本稿では、公式ドキュメントの動作を前提に、試験(CCAAK)で問われやすい要点と、運用での現実解を整理します。注意点はバージョン依存の挙動を避け、安定機能(topic 設定・producer/consumer 基本設定・log compaction の原理)に絞って解説します。
パーティション数は並列性の上限を決める一方で、1パーティションあたりのメタデータ・ページキャッシュ・ログセグメント・レプリケーションスレッド等の固定コストを持ちます。過剰に増やすと、ブローカーのメモリ消費、オープンファイル数、コントローラやメタデータ伝播の負荷が跳ね上がります。
おおまかな見積りとして、総セグメント数 ≈ パーティション数 × (アクティブ + ローテート済みセグメント)。retention.bytes/segment.bytes が大きいとセグメント数が増え、ファイルディスクリプタとディスクシークのコストが増加します。レプリケーションのネットワーク出力はおおむね 書き込みスループット × (replication.factor - 1) に比例します。
段階的なパーティション増加(縮小不可のため計画的に)
# パーティション増加。割当はクラスタのバランスを見て進める
kafka-topics.sh --bootstrap-server <broker:9092> \
--alter --topic orders --partitions 24
# 増やしすぎ注意。割り当て後は再バランスのネットワーク/ディスクI/Oも計画に入れるKafka の圧縮は基本的にプロデューサ側で行い、トピック設定 compression.type=producer(デフォルト)だとプロデューサ設定が適用されます。圧縮はディスク/ネットワーク使用量を下げる一方で、CPUコストとレイテンシに影響します。アルゴリズムによる性質差を把握し、メッセージサイズ・バッチングとの相性を見て選定します。
一般に zstd は高圧縮・高CPU、lz4 は低レイテンシ・中圧縮、snappy は軽量で安定、gzip は互換性が広いがCPUが重め、無圧縮はCPU最小だが帯域・ディスクを消費します。小さすぎるバッチでは圧縮効果が出にくいため、linger.ms と batch.size を併用して有効な単位で固めるのが定石です。
| アルゴリズム | 概ねの圧縮率 | CPUコスト傾向 | スループット/遅延への影響 |
|---|---|---|---|
| zstd | 高い(2〜5倍圧縮が出やすい) | 高 | バッチ大で高効率・CPUは重め |
| lz4 | 中(1.5〜3倍程度) | 中〜低 | 低遅延で安定、スループット良好 |
| snappy | 中(1.5〜2倍程度) | 低 | 安定・CPU軽め |
| gzip | 中〜高 | 中〜高 | CPU負荷が効くと遅延増 |
| none | なし | 最小 | 帯域・ディスクを消費 |
プロデューサの圧縮とバッチング設定例
props.put("compression.type", "zstd");
props.put("linger.ms", "15"); // レイテンシ許容範囲で調整
props.put("batch.size", "131072"); // 128KB 目安(ワークロードでABテスト)
props.put("acks", "all"); // 耐障害性と再送の無駄を抑える保持設計は delete(時間/サイズで丸ごと削除)と compact(キーごとに最新レコードを残す)の組み合わせで決めます。最新版を必ず保持したいキー付きデータ(例: エンティティ最新状態)は compact、イベント履歴は delete が基本です。両方を併用する compact,delete は、履歴を一定期間だけ保持しつつ最新版も残したい場合に有効ですが、retention を短くしすぎるとコンパクション前に削除が進み期待を外すことがあります。
retention.bytes と retention.ms はどちらか一方(または両方)で制限可能です。ストレージ予算を厳格に守りたい場合は bytes 優先、コンプライアンスで保存期間が決まる場合は ms を優先します。segment.bytes はコンパクタの効率やファイル数、ページキャッシュ効率に効くため、I/O とメモリのバランスで決めます。
delete と compact の違い(概念図)
トピック保持/コンパクションの安全な組み合わせ
# 最新版保証(履歴は不要)
kafka-configs.sh --bootstrap-server <broker> --alter \
--topic entity-state \
--add-config cleanup.policy=compact,segment.bytes=134217728,min.cleanable.dirty.ratio=0.5
# 履歴も直近は保持(compact + delete を慎重に)
kafka-configs.sh --bootstrap-server <broker> --alter \
--topic entity-state-history \
--add-config cleanup.policy=compact,delete,retention.ms=1209600000,segment.ms=604800000
# ストレージ上限を厳格化(bytes優先)
kafka-configs.sh --bootstrap-server <broker> --alter \
--topic metrics \
--add-config retention.bytes=10737418240概算ストレージ: 書き込みレートB(バイト/秒)、圧縮後比率r(0<r<=1)、保持期間T(秒)、パーティションP、レプリカR とすると、必要ディスク総量 ≈ B × r × T × R。bytes 制限を使う場合は、retention.bytes × P × R がクラスタ消費に近い上限目安になります(オーバーヘッドは別途)。
ネットワーク複製トラフィック(ブローカー内向き): B × r × (R-1)。クライアント外向きの送信はコンシューマ数やフィルタリングに依存します。見積もり段階ではピークと平常の両方を置いて上振れを吸収できるようにします。
簡易計算のメモ(シェル)
# B=20MB/s, 圧縮後 r=0.4, R=3, T=7日
B=$((20*1024*1024))
r=0.4
R=3
T=$((7*24*3600))
echo "Disk ~= $(awk -v b=$B -v r=$r -v t=$T -v R=$R 'BEGIN{printf "%.1f GiB\n", b*r*t*R/1024/1024/1024}')"プロデューサでは、linger.ms と batch.size によるバッチング、圧縮、適切な acks により、無駄な再送と小粒度送信を抑制します。レコードが小さいほどバッチ化の恩恵は大きく、ネットワーク/ディスクのオーバーヘッド削減に直結します。
コンシューマでは、fetch.min.bytes と fetch.max.wait.ms で取り込みのまとまりを作り、max.partition.fetch.bytes と session.timeout.ms をワークロードに合わせます。過小値はRPC増加とコンテキストスイッチを増やし、CPU/ネットワークコストが上がります。
コンシューマのフェッチ最適化例
props.put("fetch.min.bytes", "1048576"); // 1MB まとまり
props.put("fetch.max.wait.ms", "50"); // バッチ化の待ち
props.put("max.partition.fetch.bytes", "5242880");
props.put("enable.auto.commit", "false"); // 冪等に合わせて制御監視では、ディスク使用率(topic/partition 単位の推移)、レプリケーションの遅延(ISR・UnderReplicatedPartitions、Follower ラグ)、ネットワーク出力、コンパクション指標(ログクリーナーの進捗/JMX)、リクエスト遅延を継続可視化します。保持やコンパクションの設定変更は即時反映されるものもあるため、動的変更後は必ず挙動を追跡します。
自動化では、クォータ(プロデューサ/コンシューマ/クライアントIDごとの帯域制限)でノイジーネイバーを抑制し、ストレージしきい値でアラートと書き込み制御を組み合わせます。CCAAK では、動的設定(kafka-configs.sh)、安全なローリング適用、設定の優先順位(ブローカー < トピック < クライアント)が理解できているかが狙われます。
クォータ/クリーナースレッドの動的設定例
# クライアントIDごとのプロデュース帯域を制限(過負荷回避)
kafka-configs.sh --bootstrap-server <broker> --alter \
--add-config 'producer_byte_rate=1048576' --entity-type clients --entity-name appA
# ログクリーナースレッド(ブローカー再起動が必要な場合あり。環境により動的化可否を確認)
# server.properties: log.cleaner.threads=2CCAAK
問題 1
監査対応のため、各キーの最新版は必ず保持しつつ、古い値は可能な限り削減してストレージコストを下げたい。どのトピック設定が最も適切か?
正解: A
最新版保持を強制するには log compaction が必須。delete のみでは最新版が retention を超えると消える恐れがある。compact と delete の併用は保持期間が短いとコンパクションが追いつかず最新版が欠落するリスクがある。圧縮方式の変更だけでは保持要件を満たせない。
圧縮はブローカーでも設定できますか?どこで決めるのが正しいですか?
トピックの compression.type は "producer"(既定)を推奨。実際の圧縮はプロデューサが行い、エンドツーエンドで同一アルゴリズムを通すのが効率的です。ブローカーでの再圧縮はCPU/レイテンシのコストを生むため避けるのが無難です。
compact と delete を併用すると必ず最新版が残りますか?
最新版を確実に残したいなら compact 単独が安全です。compact,delete の併用は retention を短くするとコンパクションが完了する前に古いセグメントが delete で削除され、期待どおりの最新版保持にならない可能性があります。
パーティションを増やすときの最小限の安全策は?
段階的に増やし、ブローカーのディスク・FD・レプリケーション遅延・GC を監視します。リバランス中のネットワーク/ディスク負荷を見越してメンテナンス時間帯に実施し、必要に応じてスロットリング(クォータ)を一時的に強化します。縮小は不可なので過剰に先行しないことが重要です。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Kafka Topic と Partition の基礎: 分散とスケーラビリティの要
CCDAK 対策と実務の両立を意識し、Topic/Partition/Replica/Consumer Group の役...
CCDAK 試験ガイド:出題範囲・配点・申込み・対策
Confluent Certified Developer for Apache Kafka (CCDAK) の出題範囲...
Confluent Certified Administrator (CCAAK) 対策: 出題範囲・配点の考え方・運用観点の要点
CCAAKに向けて、試験領域の押さえどころを運用目線で整理。プロダクションで通用する設定・監視・セキュリティの実践知を、...
Kafka の Replica と In-Sync Replicas を正しく設計する: 耐障害性と一貫性
レプリカとISRの仕組みを起点に、acks と min.insync.replicas、クリーン/アンクリーンリーダー選...
Kafka の Offset とコミット: ポジション管理と at-least-once の基礎
CCDAK 対策と実務の両立を意識して、Kafka コンシューマのオフセット管理とコミット戦略を整理。at-least-...