2025년 11월 3일 작성

Kafka Log Compaction - Key 기반 상태 관리

Kafka의 log compaction은 key별 최신 message만 유지하여 storage를 효율적으로 관리하면서도 각 key의 최종 상태를 영구 보존합니다.

Kafka Log Compaction

  • Kafka log compaction은 topic의 저장 공간을 효율적으로 관리하면서도 최신 상태 정보를 영구 보존하는 핵심 mechanism입니다.
  • 전통적인 시간 기반 retention과 달리, key별 최신 message만 유지하므로 log 크기가 무한정 증가하지 않습니다.
  • database의 Change Data Capture(CDC), configuration 관리, event sourcing 등 상태 기반 system에서 필수적으로 활용됩니다.

Log Compaction의 핵심 개념

  • log compaction은 같은 key를 가진 message들 중 가장 최신 message만 보존하는 Kafka의 저장소 관리 전략입니다.
  • 시간이 지나도 각 key의 최종 상태는 항상 확인할 수 있어, 새로운 consumer가 전체 topic을 읽어도 완전한 상태 정보를 얻습니다.
  • message의 순서는 보장되며, offset 기반 처리도 정상적으로 동작합니다.

기존 Time-based Retention과의 차이점

  • Time-based retention : 설정된 시간이 지나면 message를 무조건 삭제합니다.
    • 오래된 message는 key와 관계없이 모두 사라집니다.
    • storage 사용량은 예측 가능하지만, 과거 상태 정보는 복구할 수 없습니다.
  • Log compaction : key별로 최신 message만 유지하고 오래된 message를 삭제합니다.
    • 각 key의 최종 상태는 영구 보존됩니다.
    • storage 사용량은 unique key 개수에 비례합니다.

Log Compaction이 필요한 상황

  • Database CDC : table의 각 record에 대한 최신 상태만 관리하면 되는 경우입니다.
    • primary key별로 최신 변경 사항만 유지하여 downstream system의 상태를 동기화합니다.
  • Configuration 관리 : application 설정값의 변경 이력보다는 현재 설정값이 중요한 경우입니다.
    • 설정 key별로 최신값만 보존하여 application 재시작 시 올바른 설정을 load할 수 있습니다.
  • Event sourcing : entity의 현재 상태를 빠르게 재구성해야 하는 경우입니다.
    • entity ID별로 최신 snapshot만 유지하여 state rebuilding 성능을 최적화합니다.

Log Compaction 동작 Mechanism

  • log compaction은 background process로 동작하며, 즉시 실행되지 않고 특정 조건을 만족할 때 실행됩니다.
  • compaction 과정에서 기존 segment file들을 새로운 segment로 재작성하여 중복된 key의 오래된 message들을 제거합니다.
  • 전체 과정은 non-blocking이며, compaction 중에도 producer와 consumer는 정상적으로 동작합니다.

Compaction 실행 조건

  • Segment 크기 조건 : active segment를 제외한 closed segment들이 대상이 됩니다.
    • segment.ms 또는 segment.bytes 설정에 따라 segment가 닫힙니다.
    • active segment는 compaction 대상에서 제외되어 최신 message 손실을 방지합니다.
  • Dirty Ratio 조건 : compaction 대상 data의 비율이 임계값을 초과해야 합니다.
    • min.cleanable.dirty.ratio 설정값 (기본값 0.5)을 넘어야 compaction이 시작됩니다.
    • 너무 자주 compaction하면 I/O 부하가 증가하므로 적절한 임계값이 필요합니다.
  • 최소 지연 시간 : min.compaction.lag.ms 설정만큼 대기 후 compaction을 실행합니다.
    • 같은 key에 대한 연속적인 update가 있을 때 불필요한 compaction을 방지합니다.

Compaction 처리 과정

  1. Segment 분석 : compaction 대상 segment들을 scan하여 key별 최신 offset을 파악합니다.
    • 각 key의 가장 높은 offset을 가진 message를 보존 대상으로 marking합니다.
    • 이 과정에서 memory에 key-offset mapping table을 구성합니다.
  2. 새로운 Segment 생성 : 보존 대상 message들만 모아서 새로운 segment file을 생성합니다.
    • message의 순서와 offset은 그대로 유지됩니다.
    • 압축률은 key 중복도에 따라 결정됩니다.
  3. Atomic 교체 : 기존 segment들을 새로운 segment로 원자적으로 교체합니다.
    • consumer가 읽는 도중에도 일관성이 보장됩니다.
    • 교체 완료 후 기존 segment file들은 삭제됩니다.

Tombstone을 통한 삭제 처리

  • log compaction 환경에서는 특정 key를 완전히 삭제하기 위한 특별한 mechanism이 필요합니다.

  • tombstonevalue=null로 설정된 특별한 message로, 해당 key가 논리적으로 삭제되었음을 표시합니다.
    • 일반 message와 동일한 key를 가지지만 value=null로 설정된 특별한 message입니다.
    • headers, timestamp 등 다른 metadata는 정상적으로 포함됩니다.
    • producer가 명시적으로 ProducerRecord(key, null)로 전송해야 합니다.
  • tombstone은 Kafka에게 “이 key는 더 이상 존재하지 않는다”고 알리는 표준 signal입니다.
    • 단순한 null 값이 아니라 삭제 명령으로 해석됩니다.
    • log compaction 과정에서 특별하게 처리됩니다.
  • tombstone을 통해 compaction 후에도 삭제된 key가 재생성되지 않음을 보장합니다.

Tombstone 처리 과정

  • 생성 시점 : application이 특정 key를 삭제하고 싶을 때 tombstone을 명시적으로 전송합니다.
    • database의 DELETE 연산을 CDC로 처리할 때 자주 사용됩니다.
    • configuration 삭제나 entity 제거 시에도 활용됩니다.
  • Compaction 중 처리 : tombstone은 해당 key의 모든 이전 message들을 제거 대상으로 marking합니다.
    • 첫 번째 compaction에서는 tombstone만 남고 이전 message들이 삭제됩니다.
    • 이후 compaction에서는 tombstone 자체도 삭제 대상이 될 수 있습니다.
  • 최종 삭제 : delete.retention.ms 설정에 따라 tombstone도 완전히 삭제됩니다.
    • 기본값은 24시간이며, 이 시간 동안은 tombstone이 유지됩니다.
    • 충분한 시간을 두어 모든 consumer가 삭제 정보를 인지할 수 있도록 합니다.

Tombstone 활용 시 주의 사항

  • Consumer 처리 : consumer는 value=null인 message를 받았을 때 적절한 삭제 logic을 구현해야 합니다.
    • 단순히 null check만 하는 것이 아니라 삭제 의미로 해석해야 합니다.
    • local cache나 database에서 해당 key를 제거하는 작업이 필요합니다.
  • Producer 설계 : tombstone 전송 전에 일반 삭제 event를 먼저 보내는 것이 좋습니다.
    • CDC 도구들이 이런 pattern을 사용하여 삭제 정보와 삭제 marking을 분리합니다.
    • consumer가 삭제 이유나 삭제된 data를 확인할 수 있게 합니다.

Log Compaction 설정 및 최적화

  • log compaction을 효과적으로 활용하려면 workload 특성에 맞는 설정이 필요합니다.
  • 잘못된 설정은 storage 효율성 저하compaction 지연을 초래할 수 있습니다.
  • 각 설정값의 의미를 정확히 이해하고 monitoring을 통해 지속적으로 조정해야 합니다.

핵심 설정 Parameter

  • cleanup.policy=compact : topic에서 log compaction을 활성화하는 필수 설정입니다.
    • delete와 함께 사용하여 compact,delete로 설정하면 hybrid 방식으로 동작합니다.
    • 시간 기반 retention과 compaction을 동시에 적용할 수 있습니다.
  • min.cleanable.dirty.ratio : compaction 실행 임계값을 조정하는 핵심 설정입니다.
    • 값이 작을수록 compaction이 자주 실행되어 storage 효율성은 높아지지만 CPU 부하가 증가합니다.
    • 값이 클수록 compaction 빈도는 줄어들지만 중복 data가 오래 남아있습니다.
  • segment.ms / segment.bytes : compaction 대상이 되는 segment 생성 주기를 결정합니다.
    • 값이 작을수록 compaction이 빨리 시작되지만 작은 segment들이 많이 생성됩니다.
    • 값이 클수록 compaction 지연이 발생하지만 I/O 효율성은 높아집니다.

성능 최적화 전략

  • Memory 할당 최적화 : compaction 과정에서 key-offset mapping을 위한 충분한 heap memory가 필요합니다.
    • log.cleaner.dedupe.buffer.size 설정으로 compaction 전용 memory를 조정합니다.
    • unique key 개수가 많은 topic일수록 더 많은 memory가 필요합니다.
  • Parallel Processing : log.cleaner.threads 설정으로 compaction 병렬 처리 수준을 조정합니다.
    • thread 수를 늘리면 여러 topic의 compaction을 동시에 처리할 수 있습니다.
    • 과도한 병렬화는 disk I/O 경합을 유발할 수 있으므로 주의가 필요합니다.
  • I/O 최적화 : compaction 작업의 disk I/O 부하를 분산시키는 것이 중요합니다.
    • log.cleaner.io.max.bytes.per.second 설정으로 compaction I/O를 제한할 수 있습니다.
    • peak time을 피해 compaction이 실행되도록 min.compaction.lag.ms를 조정합니다.

Monitoring 지표

  • Compaction rate : kafka.log:type=LogCleanerManager,name=cleaner-recopy-percent metric으로 compaction 효율성을 측정합니다.
    • 높은 recopy rate는 중복 data가 많음을 의미합니다.
    • 낮은 rate는 이미 잘 압축된 상태임을 나타냅니다.
  • Lag monitoring : compaction 대기 중인 dirty data의 크기와 비율을 지속적으로 확인합니다.
    • kafka.log:type=Log,name=size,topic=*,partition=* metric으로 전체 log 크기를 추적합니다.
    • dirty ratio가 지속적으로 높다면 compaction 설정을 조정해야 합니다.

실무 활용 사례와 고려 사항

  • log compaction은 특정 use case에 최적화된 기능이므로, 모든 상황에 적합하지는 않습니다.
  • 도입 전에 data access pattern과 consistency 요구 사항을 면밀히 분석해야 합니다.
  • 기존 system과의 호환성 문제도 충분히 검토해야 합니다.

적합한 활용 사례

  • Database Change Data Capture : 각 table row의 최신 상태만 관리하면 되는 CDC pipeline에서 효과적입니다.
    • primary key를 Kafka message key로 사용하여 row별 최신 변경사항만 유지합니다.
    • downstream system이 전체 dataset을 재구성할 때 전체 scan 시간을 크게 단축합니다.
  • Configuration Store : application 설정값의 중앙집중식 관리에 활용할 수 있습니다.
    • 설정 key별로 최신값만 보존하여 application 재시작 시 빠른 설정 load가 가능합니다.
    • 설정 변경 이력보다는 현재 유효한 설정값이 중요한 환경에 적합합니다.
  • User State Management : user profile이나 session 정보 같은 user별 상태 data 관리에 효과적입니다.
    • user ID를 key로 사용하여 각 user의 최신 상태만 유지합니다.
    • real-time personalization이나 recommendation system에서 빠른 user state 조회가 가능합니다.

부적합한 활용 사례

  • Event Logging : 모든 event의 완전한 기록이 필요한 audit logging에는 적합하지 않습니다.
    • log compaction은 중간 event들을 삭제하므로 완전한 audit trail을 보장할 수 없습니다.
    • 규제 요구 사항이 있는 금융이나 의료 분야에서는 주의가 필요합니다.
  • Time Series Data : 시간 순서대로 모든 측정값을 보존해야 하는 monitoring이나 analytics 용도에는 부적합합니다.
    • 같은 sensor ID라도 모든 시점의 측정값이 중요하기 때문입니다.
    • time-based retention이 더 적절한 선택입니다.
  • Message Queue : 일회성 작업 요청이나 command 전달 용도로는 적합하지 않습니다.
    • 같은 작업 ID로 여러 번 요청이 와도 모든 요청을 처리해야 하는 경우가 많습니다.
    • compaction으로 인해 중간 요청들이 사라지면 business logic에 문제가 발생할 수 있습니다.

Migration 고려 사항

  • 기존 Consumer 호환성 : 기존에 time-based retention을 사용하던 consumer들이 compaction 동작을 올바르게 처리할 수 있는지 확인해야 합니다.
    • tombstone message 처리 logic이 구현되어 있는지 점검합니다.
    • consumer offset 관리 방식이 compaction과 충돌하지 않는지 검증합니다.
  • Storage 사용량 변화 : compaction 도입 후 disk 사용 pattern이 크게 변경될 수 있습니다.
    • key 중복도가 높은 topic은 storage 사용량이 크게 감소합니다.
    • 반대로 unique key가 많은 topic은 예상보다 공간 절약 효과가 적을 수 있습니다.
  • Performance 영향 : compaction background 작업의 I/O 부하가 기존 workload에 미치는 영향을 사전에 test해야 합니다.
    • peak time에 compaction이 실행되면 producer/consumer 성능이 저하될 수 있습니다.
    • compaction thread와 memory 할당을 적절히 조정하여 resource contention을 최소화해야 합니다.

Reference


목차