Kafka

Kafka Log Compaction 徹底理解: キー単位の最新値保持と実務適用

2026-04-19
NicheeLab編集部

ログ圧縮は、同一キーの古いレコードをバックグラウンドで間引き、少なくとも最新(最後に書かれた)値を保持するKafkaのクリーンアップ方式です。履歴をすべて残すのではなく、最新の状態を取り出したい用途に有効です。

本稿では、仕組み・保証・代表設定・適用シーン・運用の勘所を、試験での出題ポイントと合わせて解説します。特に、tombstone(null値)の扱い、compactとdeleteの併用、セグメントとクリーンナーの関係は重点項目です。

1. Log Compactionの基本と保証

ログ圧縮は、トピックのcleanup.policy=compactを有効にすると、パーティション内の各キーについて「最後に観測されたレコード」(last write)を少なくとも1件保持します。これにより、コンシューマはトピックを最初から読むだけで、最新状態のマップ(キー→値)を再構築できます。

値がnullのレコード(通称tombstone)は、そのキーの削除を意味します。tombstone自体はdelete.retention.msの期間だけ保持され、その後のクリーンで物理的に除去されます。ログ圧縮は即時ではなく、バックグラウンドで非同期に進みます。

  • 単位はパーティション: 同じキーは同一パーティションにマップされる(ハッシュ)。キー間の最新値保証はパーティション内で成立。
  • 順序は保持: 圧縮後も残存レコードの相対順序は維持されます。
  • クリーン対象は「閉じたセグメント」: 現在書き込み中のセグメントは圧縮対象外。
  • tombstoneは削除指示: 一定期間保持後、当該キーの古い値とともに消去されます。
  • キー必須: 値だけでキーがないレコードは圧縮できない(無関係扱い)。
クリーンアップ方式保持基準主な用途
delete時間/サイズ(retention.ms/bytes)完全履歴が必要なイベントログ
compactキーごとの最新値(+最近の未圧縮領域)状態同期、キャッシュ、参照データ
compact,delete最新値+古いセグメントの期限削除最新値を保ちつつディスクを強力制限

キーA/Bの更新と圧縮の概念図

Partition P0 (時系列 →)
| A:1 | B:x | A:2 | A:3 | B:y | A:null | B:z |
            ^  古いAはA:3により不要
                       ^  A:nullはAの削除指示(tombstone)
圧縮後(概念): | ... | A:null | B:z |
結果: Aは削除、Bは最新zが保持

キー付きで投入する例(console-producer)

kafka-console-producer \
  --broker-list localhost:9092 \
  --topic users-compact \
  --property parse.key=true \
  --property key.separator=:
# 例: userId:json
u1:{"name":"Ann","v":1}
u1:{"name":"Ann","v":2}
u2:{"name":"Bob","v":1}
# 圧縮後、u1はv=2のみが残る(しばらく後に)

2. セグメントとログクリーナーの内部動作

パーティションは複数のセグメントに分割されます。書き込み中のアクティブセグメントは対象外で、ローテーション済み(閉じた)セグメントがクリーンの候補になります。クリーンはキーごとの最新オフセットをインデックス化し、古い重複を間引いた新しいセグメントへ再書き込みします。

どの程度“汚れて”いれば(重複が多ければ)クリーンするかはmin.cleanable.dirty.ratioや関連しきい値で制御されます。クリーナースレッド数、I/Oスループット、圧縮形式は独立で、クリーンは時間基準では実行されません。

  • クリーンはブローカープロセス内で動作し、レプリカごとに独立に実施される。
  • クリーン後は新セグメントが有効化され、旧セグメントは削除候補になる(完全に不要なら物理削除)。
  • tombstoneはdelete.retention.msの間は残り、同一キーの復活(再投入)があれば削除扱いは打ち消される。
設定/概念スコープ役割/要点
log.cleaner.enableブローカーログクリーナーの有効化(通常は有効)
log.cleaner.threadsブローカー並行クリーニング数の調整
min.cleanable.dirty.ratio / min.cleanable.dirty.ratio(トピック)両方どの程度の重複が溜まったらクリーンするかの目安

セグメントのクリーンの流れ

Before:
[Seg-1(closed)] [Seg-2(closed)] [Seg-3(active)]
  A:1 B:1 A:2     B:2 A:3        ...
Cleaner →
  - 各キーの最新(A:3, B:2)を抽出
  - 新しいクリーン済みセグメントへ再配置
After:
[Seg-1'(cleaned: A:3 B:2)] [Seg-3(active)]
旧Seg-1/2は削除候補

セグメント内容を検査(kafka-dump-log.sh)

kafka-dump-log.sh --skip-record-metadata --print-data-log \
  --files /var/lib/kafka/data/users-compact-0/00000000000000000000.log | head -n 50
# 圧縮の前後でキーごとの残存レコードを比較して確認する

3. 主要設定と試験での落とし穴

ログ圧縮はトピック単位で有効化し、ブローカー既定のしきい値をトピックで上書き可能です。特にcleanup.policy、delete.retention.ms、min.cleanable.dirty.ratio、segment.ms/segment.bytes、min.compaction.lag.ms/max.compaction.lag.msの相互作用を押さえます。

compact,deleteを併用すると、最新値を保持しながら古い完全クリーン済みセグメントを期限で削除できます。tombstoneはdelete.retention.msの間は残るため、即時に完全消去はされません。試験では「キー必須」「tombstoneの意味」「クリーンは非同期」の3点が頻出です。

  • cleanup.policy=compact または compact,delete を明示設定する。
  • delete.retention.ms は tombstone の保持期間を決める。短すぎると遅延コンシューマの再構築に影響。
  • min.compaction.lag.ms は“最低いつまで圧縮しないか”の待機時間。取り違え注意。
  • セグメントがローテートされないとクリーン対象にならないため、segment.ms/bytesも重要。
パラメータ出題観点注意点
cleanup.policycompactとdeleteの違い併用時は“最新値保持+期限削除”の両方が効く
delete.retention.mstombstoneの寿命短いと復旧不能リスク、長いとディスク圧迫
min.compaction.lag.ms/max.compaction.lag.ms圧縮タイミング早すぎ/遅すぎ双方の影響を理解する

retentionとcompactionの適用順序イメージ

書き込み → セグメントローテーション → (閾値到達)Compaction →
[compactのみ] 最新値を保持
[compact,delete] さらに“完全クリーン済みかつ期限超”のセグメントを削除

トピック作成時にcompactionを有効化

kafka-topics.sh --create \
  --bootstrap-server localhost:9092 \
  --topic users-compact \
  --partitions 6 \
  --replication-factor 3 \
  --config cleanup.policy=compact \
  --config min.cleanable.dirty.ratio=0.5 \
  --config delete.retention.ms=86400000 \
  --config segment.ms=3600000

4. 適用シーンとアンチパターン

典型的な適用は、CDCの更新ストリーム(顧客の最新住所、在庫残量)、キャッシュのウォームアップ/更新、Kafka Streamsの状態ストア(changelog)です。いずれも“最新状態”が重要で、過去の細かな更新履歴は不要です。

アンチパターンは、完全履歴が不可欠な監査ログ、順序通りの全イベント再生が必要なイベントソーシング、キーが無い(またはほぼユニークで更新の無い)データです。これらはdeleteベースの保持か、別のストレージを選ぶべきです。

  • CDC + compaction: Debezium等のUpdate/Deleteイベントと相性が良い。
  • キャッシュ再構築: earliestから読み、最終マップを構築。
  • 状態ストア: Streamsのchangelogトピックはcompact推奨。
  • アンチ: キー無し、更新が一度きりのイベント、履歴完全保存が要件。
シナリオ推奨トピック方式注意点
顧客プロファイル最新値compactキー設計(同一顧客→同一キー)必須
在庫残量同期compact,deleteディスク制限しつつ最新を保持
監査・追跡ログdelete完全履歴が要件。圧縮は不適

CDCから最新ビュー構築までの流れ

DB → CDC(更新/削除) → [compacted topic] →
            → キャッシュ/ビュー(キーごとの最新のみ)
削除イベントはtombstoneとして流れ、一定期間後に物理削除

tombstoneを送る(Java Producer)

Properties p = new Properties();
p.put("bootstrap.servers", "localhost:9092");
p.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
p.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
try (KafkaProducer<String, String> producer = new KafkaProducer<>(p)) {
    // 通常の最新値
    producer.send(new ProducerRecord<>("users-compact", "u1", "{\"name\":\"Ann\"}"));
    // 削除(tombstone): 値にnullを指定
    producer.send(new ProducerRecord<>("users-compact", "u1", null));
    producer.flush();
}

5. 運用・監視・トラブル対処

圧縮は非同期で、負荷としきい値に左右されます。監視では、ログクリーナースレッドの稼働状況、クリーン対象バイト量、ディスク使用量、クリーンのバックログを追います。トピックごとの設定差分も定期点検します。

“圧縮されない/遅い/消えない”は定番の相談です。キーポイントは、(1)セグメントが閉じていない、(2)dirty比率が低い、(3)tombstone保持期間内、(4)キー無しレコード混在、(5)クリーナーのスループット不足、のいずれかであることが多いです。

  • まず設定を確認: cleanup.policy、min.cleanable.dirty.ratio、segment.ms/bytes、delete.retention.ms。
  • ブローカーのログとJMXでクリーナーの進捗とエラーを確認。
  • ディスク水位・I/O競合が強いとクリーンが進みにくい。スレッド数やI/O帯域を調整。
症状主因の例対処の方向性
圧縮が進まないセグメント未ローテート/dirty比率不足segment.ms/bytes見直し、しきい値調整
削除されないdelete.retention.ms期間内保持期間の理解/調整、待機
ディスク逼迫compactのみで高頻度更新compact,delete併用やスレッド増強/圧縮設定見直し

tombstoneの寿命タイムライン

Write key=K, value=null (tombstone)
  ↓ 保持(delete.retention.ms)
Compaction removes K's old values
  ↓ 期限後
Tombstone自体も物理削除

運用時の設定確認/変更

# 設定確認
kafka-configs.sh --bootstrap-server localhost:9092 \
  --entity-type topics --entity-name users-compact --describe

# 動的変更(例): dirty比率を調整
kafka-configs.sh --bootstrap-server localhost:9092 \
  --entity-type topics --entity-name users-compact \
  --alter --add-config min.cleanable.dirty.ratio=0.4

6. 実装例と移行戦略

既存のdeleteベースのトピックからcompactまたはcompact,deleteへ移行する場合は、(1)キー付きで再発行できるか、(2)初期状態のバックフィル手段があるか、を先に確認します。キーが無いと圧縮の恩恵を受けません。

青/緑切替が安全です。新トピックをcompactで作成→バックフィル→新旧両配信→コンシューマ切替→旧トピック廃止の順で進めると、ダウンタイムとロールバックリスクを抑えられます。

  • 移行時は“earliestから読み直せば最新ビューが作れること”を検証。
  • compact,deleteを使うならretention.ms設計も併せて行う。
  • Streams/KConnectなどミドル層で確実にキーを付与してから出力。
移行オプション長所注意点
青/緑(新トピック併設)安全・段階移行二重配信期間のコスト
同一トピック設定切替シンプル既存データは圧縮対象にならず効果発現に時間
Streamsで集約→compact出力同時に品質向上アプリ開発が必要

青/緑移行の流れ

Producers → [old-topic(delete)] → Consumers(旧)
          ↘︎ 変換/バックフィル ↘︎
            [new-topic(compact)] → Consumers(新)
切替後にold-topicを段階廃止

最新値のみを書き出すStreamsトポロジ(例)

StreamsBuilder b = new StreamsBuilder();
KStream<String, String> s = b.stream("src");
KTable<String, String> latest = s.groupByKey().reduce((agg, v) -> v);
latest.toStream().to("dst-compacted");
// dst-compacted は cleanup.policy=compact で作成しておく

問題で確認

CCDAK / CCAAK

問題 1

Kafkaのログ圧縮トピックで、キーKの削除を確実に反映させたい。正しいアプローチはどれか。

  1. 値がnullのレコード(いわゆるtombstone)をキーKで送信する
  2. 圧縮を一時的に無効化してからretention.msを0にする
  3. キーKの古いレコードをすべて再送して上書きする
  4. コンシューマグループをリセットして最新のみを読む

正解: A

ログ圧縮における削除は、値がnullのレコード(tombstone)で表現する。tombstoneはdelete.retention.msの期間保持された後、クリーンによって古い値とともに物理削除される。他の選択肢は削除を意味せず、正しくない。

よくある質問

ログ圧縮はレコードの順序を壊しますか?

いいえ。圧縮後も、残ったレコード間の相対順序はパーティション内で維持されます。圧縮は古い重複を間引くだけで、順序の入れ替えは行いません。

compact,deleteを併用すると最新値が消えることはありますか?

通常はありません。クリーンによりキーの最新値だけが新しいセグメントへ再配置され、古い完全クリーン済みセグメントが期限で削除されます。結果として少なくとも最新値(またはtombstone)は保持されます。

コンシューマはどのオフセットから読めば最新ビューを再構築できますか?

最新ビューを初期化する場合はearliestからの全読込が推奨です。ログ圧縮は古い重複を消すだけで、最新値の再構築には“残った全レコード”の適用が必要です。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
Kafka

Kafka Topic と Partition の基礎: 分散とスケーラビリティの要

CCDAK 対策と実務の両立を意識し、Topic/Partition/Replica/Consumer Group の役...

Kafka

CCDAK 試験ガイド:出題範囲・配点・申込み・対策

Confluent Certified Developer for Apache Kafka (CCDAK) の出題範囲...

Kafka

Confluent Certified Administrator (CCAAK) 対策: 出題範囲・配点の考え方・運用観点の要点

CCAAKに向けて、試験領域の押さえどころを運用目線で整理。プロダクションで通用する設定・監視・セキュリティの実践知を、...

Kafka

Kafka の Replica と In-Sync Replicas を正しく設計する: 耐障害性と一貫性

レプリカとISRの仕組みを起点に、acks と min.insync.replicas、クリーン/アンクリーンリーダー選...

Kafka

Kafka の Offset とコミット: ポジション管理と at-least-once の基礎

CCDAK 対策と実務の両立を意識して、Kafka コンシューマのオフセット管理とコミット戦略を整理。at-least-...

Kafkaの記事一覧 (100件)
© 2026 NicheeLab All rights reserved.