Engineering Note
Kafka partition은 괜찮다는데 디스크가 없다
Kafka 4.3의 Partition Size Percentage metrics가 retention 압력을 보여주는 방식과 한계, 그리고 log.dirs 물리 free space 모니터링이 여전히 필요한 이유를 정리합니다.
Kafka broker의 디스크 여유 공간은 재미있는 지표가 아닙니다.
그런데 운영 화면에서 이런 장면을 만나면 이야기가 달라집니다.
topic-a-0 RetentionSizeInPercent: 15%
topic-b-2 RetentionSizeInPercent: 18%
topic-c-1 RetentionSizeInPercent: 12%
/data/kafka-logs filesystem available: 3%
개별 partition은 아직 retention 한도에 멀어 보입니다. 하지만 broker가 실제로 더 쓸 수 있는 disk는 거의 남지 않았습니다. 이때 broker를 멈추게 하는 것은 낮은 partition percentage가 아니라 log.dirs 아래의 물리 free space입니다.
그래서 디스크 여유 공간은 Kafka 운영에서 가장 현실적인 지표 중 하나입니다. log.dirs가 가리키는 파일시스템이 꽉 차면 broker는 더 이상 추상적인 메시징 시스템이 아닙니다. append해야 할 log segment가 있고, replica가 따라와야 하고, retention cleanup이 돌아야 하고, 운영자는 그 모든 일이 같은 물리 디스크 위에서 벌어진다는 사실을 다시 보게 됩니다.
Apache Kafka 4.3에는 이 영역을 더 잘 보기 위한 새 메트릭이 추가됐습니다.
KIP-1257: Partition Size Percentage Metrics for Storage Monitoring
이 메트릭은 유용합니다. 특히 partition이 자기 retention 한도에 얼마나 가까워졌는지 바로 볼 수 있게 해줍니다.
그렇지만 이 메트릭이 df -h나 node exporter의 filesystem free space 알람을 대체하지는 않습니다. Kafka를 운영한다면 log.dirs의 물리 free space는 선택적으로 보면 좋은 지표가 아니라 반드시 관리해야 하는 지표입니다.
이 글에서는 Kafka 4.3의 partition size percentage 메트릭이 무엇을 해결하는지, 무엇을 해결하지 않는지, 그리고 애플리케이션 대용량 메시지 테스트에서 왜 log.dirs의 실제 free space를 끝까지 봐야 하는지 정리합니다.
log.dirs는 Kafka의 물리적인 바닥이다
Kafka에서 topic은 partition으로 나뉘고, 각 partition은 broker의 log directory 아래에 실제 directory와 segment file로 저장됩니다. Kafka 문서도 각 sharded partition log가 Kafka log directory 아래의 독립된 folder로 놓인다고 설명합니다.
그래서 운영 관점에서는 topic보다 한 단계 아래를 봐야 합니다.
topic
-> partition
-> replica
-> broker
-> log.dir
-> filesystem free space
Kafka가 retention을 관리하고, replica를 옮기고, consumer가 offset을 따라가더라도 마지막에는 log.dirs의 파일시스템에 byte가 쓰입니다. 이 계층이 꽉 차면 문제는 모호한 성능 저하가 아니라 쓰기 실패입니다.
Kafka 입장에서는 disk full이 보통 log segment append, index append, checkpoint, flush 같은 경로에서 No space left on device 계열의 IOException으로 나타납니다. 그러면 해당 log directory는 실패한 저장 경로가 되고, Kafka는 그 directory를 offline으로 취급합니다.
여기서 구성에 따라 결과가 갈립니다.
log.dirs가 여러 개 있고 일부만 실패:
broker는 남은 live log directory로 계속 떠 있을 수 있다.
하지만 실패한 directory의 replica는 offline이 되고,
OfflineLogDirectoryCount가 0보다 커진다.
단일 log.dir이거나 모든 log.dirs가 실패:
broker가 더 이상 쓸 live log directory를 갖지 못한다.
이 경우 broker shutdown으로 이어진다.
KRaft 모드에서는 한 가지를 더 봐야 합니다. metadata.log.dir를 따로 지정하지 않으면 metadata log는 첫 번째 log.dirs에 놓입니다. 그래서 여러 log.dirs를 쓰더라도 metadata log가 있는 filesystem이 full에 닿으면 일반 data log directory 하나가 offline되는 것보다 더 치명적인 장애로 번질 수 있습니다.
즉 disk full은 “조금 느려질 수 있는 상태”가 아니라 broker나 replica availability를 직접 깨뜨리는 상태입니다. produce latency, follower lag, reassignment 지연 같은 신호는 그 전에 보일 수 있는 전조이거나 주변 증상일 뿐입니다. log directory가 실제로 full에 닿으면 이미 너무 늦습니다.
Kafka 4.3의 새 partition percentage 메트릭
Kafka 4.3에서 소개된 KIP-1257은 partition storage를 retention 기준의 percentage로 노출합니다. 기존에는 partition size를 byte 단위로 볼 수 있었지만, 그 값만으로는 “이 partition이 설정된 retention 한도에 얼마나 가까운가”를 바로 알기 어려웠습니다.
예를 들어 두 topic이 있다고 해보겠습니다.
| topic | partition size | retention.bytes | 해석 |
|---|---|---|---|
small-events | 20 GiB | 100 GiB | 20% |
audit-archive | 20 GiB | 2 TiB | 1% 미만 |
둘 다 20 GiB이지만 운영 의미는 다릅니다. absolute size만 보면 두 partition은 같아 보입니다. percentage로 보면 하나는 retention 한도의 20%를 쓰고 있고, 다른 하나는 아직 여유가 큽니다.
KIP-1257은 이 차이를 JMX metric으로 보여주려는 기능입니다.
비 tiered storage topic에서는 다음 metric을 봅니다.
kafka.log:type=Log,name=RetentionSizeInPercent,topic=<topic>,partition=<partition>
tiered storage topic에서는 remote log manager 쪽 metric도 추가됩니다.
kafka.log.remote:type=RemoteLogManager,name=RetentionSizeInPercent,topic=<topic>,partition=<partition>
kafka.log.remote:type=RemoteLogManager,name=LocalRetentionSizeInPercent,topic=<topic>,partition=<partition>
특히 LocalRetentionSizeInPercent는 tiered storage를 쓰는 topic에서 local retention 압력을 따로 보는 데 의미가 있습니다. remote storage를 쓰더라도 broker의 local disk는 여전히 hot data, active segment, local cache, fetch path를 감당해야 하기 때문입니다.
이 메트릭이 좋은 이유는 분명합니다.
- topic마다 retention.bytes가 달라도 같은 percentage 기준으로 볼 수 있습니다.
- partition granularity라서 특정 partition만 비정상적으로 커지는 상황을 찾기 쉽습니다.
- tiered storage 환경에서 total retention과 local retention을 분리해 볼 수 있습니다.
- alert threshold를 byte보다 의미 있게 잡을 수 있습니다.
예를 들어 RetentionSizeInPercent > 80은 “이 partition이 retention 한도에 가까워지고 있다”는 신호로 읽기 좋습니다.
하지만 이것은 free space metric이 아니다
중요한 구분이 있습니다.
RetentionSizeInPercent:
partition size / configured retention limit
filesystem free space:
log.dir가 놓인 실제 filesystem의 남은 공간
둘은 비슷해 보이지만 다른 질문에 답합니다.
RetentionSizeInPercent는 “이 partition이 자기 retention 정책 안에서 얼마나 찼는가”를 묻습니다. 반대로 log.dirs free space는 “이 broker가 지금 계속 쓸 수 있는 물리 공간이 남아 있는가”를 묻습니다.
운영에서 정말 위험한 순간은 후자입니다.
다음 상황을 생각해봅시다.
broker-1 /data/kafka-a:
topic-a-0: 15% of retention.bytes
topic-b-2: 18% of retention.bytes
topic-c-1: 12% of retention.bytes
...
filesystem available: 3%
개별 partition percentage는 모두 낮을 수 있습니다. 하지만 같은 log directory에 많은 partition이 모여 있고, retention.bytes가 실제 disk capacity보다 넉넉하게 잡혀 있다면 물리 free space는 먼저 바닥날 수 있습니다.
반대도 가능합니다.
topic-x-0:
RetentionSizeInPercent = 95
filesystem available:
45%
이 경우 partition은 retention 한도에 가깝지만 broker disk 자체는 아직 여유가 있습니다. topic owner에게는 중요한 신호지만, broker가 즉시 disk full로 죽을 상황은 아닐 수 있습니다.
그래서 두 지표는 서로 대체 관계가 아니라 서로 다른 층의 신호입니다.
| 질문 | 봐야 할 신호 |
|---|---|
| 이 partition이 retention 한도에 가까운가? | RetentionSizeInPercent |
| tiered topic의 local disk 사용이 local retention 한도에 가까운가? | LocalRetentionSizeInPercent |
| 특정 partition이 절대적으로 얼마나 큰가? | kafka.log:type=Log,name=Size,... |
| 이 broker의 log.dir가 실제로 더 쓸 수 있는가? | filesystem available/free bytes |
| 이미 log directory가 빠졌는가? | LogDirectoryOffline |
percentage metric의 한계
KIP-1257의 metric은 좋은 신호지만, 의도한 범위를 넘겨 해석하면 위험합니다.
첫째, per-partition metric입니다. 같은 disk 위에 올라간 partition들의 총합을 자동으로 보여주지 않습니다. 운영자는 partition metric을 log.dir, broker, filesystem 단위의 신호와 다시 연결해야 합니다.
둘째, retention 설정을 기준으로 계산됩니다. retention.bytes나 local.retention.bytes가 실제 disk capacity보다 크게 잡혀 있으면 percentage는 낮게 보일 수 있습니다. retention 한도는 운영 의도이고, filesystem capacity는 물리 제약입니다.
셋째, unlimited retention이나 retention 미설정에서는 의미가 약해집니다. KIP-1257은 unlimited retention에서 0을 반환하는 semantic을 둡니다. 이 값은 “사용량이 없다”가 아니라 “percentage 계산의 기준이 없다”에 가깝습니다.
넷째, cleanup은 즉시 일어나지 않습니다. KIP 문서도 metric이 100%를 넘을 수 있다고 설명합니다. segment가 닫혀야 삭제 대상이 되고, cleanup thread가 돌아야 하며, active segment나 delayed cleanup 때문에 retention 한도를 넘는 시간이 생길 수 있습니다.
다섯째, Kafka data만 disk를 쓰는 것이 아닙니다. 같은 volume에 OS log, application log, heap dump, crash dump, monitoring agent spool, backup residue가 같이 놓이면 Kafka percentage metric은 그 공간을 보지 못합니다.
정리하면 이렇습니다.
Partition percentage는 retention pressure를 보여준다.
Physical free space는 broker 생존 여유를 보여준다.
둘 다 봐야 한다.
물리 free space는 어떻게 봐야 하나
Kafka broker의 disk monitoring은 topic이나 partition보다 아래 계층에서 시작해야 합니다. log.dirs의 물리 free space는 “나중에 장애가 나면 확인할 값”이 아니라, 평소에 대시보드와 알람으로 관리해야 하는 운영 기준입니다.
운영에서 최소한 다음을 log.dirs 경로별로 봐야 합니다.
- available bytes
- used percent
- free inode count
- write latency와 device utilization
- available bytes의 감소 속도
kafka.log:type=LogManager,name=OfflineLogDirectoryCount
Prometheus node exporter를 쓴다면 node_filesystem_avail_bytes와 node_filesystem_size_bytes를 log.dirs mountpoint 기준으로 보는 식입니다. Cloud 환경에서는 EBS, Persistent Disk, managed volume의 free space와 write throttling 지표도 같이 봐야 합니다. Container 환경이라면 hostPath, PVC, local PV가 실제 어떤 device에 붙어 있는지까지 확인해야 합니다.
이 지점은 이전에 쓴 JVM 메트릭만으로는 컨테이너를 설명할 수 없다와도 이어집니다. node-metrics-agent는 애초에 Kafka 같은 JVM 기반 서버를 컨테이너에서 운영할 때, JVM/JMX 지표만으로는 broker 주변 filesystem과 I/O 상태를 설명하기 어렵다는 필요에서 시작된 도구입니다. 이미 JMX exporter를 표준 수집 경로로 쓰는 환경이라면, log.dirs 같은 Kafka storage path의 filesystem 신호를 같은 JMX/Prometheus 흐름 안으로 가져오는 역할을 할 수 있습니다.
즉 선택지는 하나가 아닙니다.
node_exporter:
host 또는 node 관점에서 mountpoint filesystem을 본다.
node-metrics-agent:
Kafka JVM이 놓인 실행 환경 관점에서 filesystem path를 JMX로 노출한다.
node-metrics-agent 쪽에서는 Kafka storage path를 설정하면 filesystem metric이 path별 MBean으로 드러납니다.
co.pletor.node:type=FsMetrics,path=/data/kafka-logs
이 MBean을 JMX exporter rule로 Prometheus metric에 매핑하면, Kafka broker JMX와 같은 scrape 흐름에서 /data/kafka-logs의 여유 공간, 사용률, inode, path별 상태를 함께 볼 수 있습니다. init-kafka-config --server-properties ... 흐름을 쓰면 Kafka server.properties의 log.dirs를 기준으로 filesystem path 설정을 만들 수 있지만, 생성된 path가 실제 container mount와 일치하는지는 배포 환경에서 다시 확인해야 합니다.
둘 중 무엇을 쓰든 핵심은 같습니다. Kafka broker가 JVM 위에서 돈다고 해서 JVM heap, GC, broker JMX만 보면 충분한 것은 아닙니다. 컨테이너가 보는 mounted filesystem, cgroup, I/O 경계가 실제로 broker의 쓰기 여유를 결정할 수 있습니다.
알람은 percent 하나로 끝내지 않는 편이 좋습니다.
절대 여유 공간:
available bytes < 100 GiB
비율:
available percent < 15%
소진 속도:
current free space / recent consumption rate < 6 hours
숫자는 환경에 따라 달라야 합니다. 중요한 것은 “몇 퍼센트 남았는가”와 “몇 시간 뒤 0이 되는가”를 같이 보는 것입니다. Kafka는 burst와 replay가 있는 시스템이므로, free space가 천천히 줄어드는 날보다 갑자기 줄어드는 테스트와 장애 대응 중에 더 위험해집니다.
대용량 메시지 테스트가 특히 위험한 이유
애플리케이션에서 대용량 메시지를 테스트할 때는 더 조심해야 합니다.
Kafka는 큰 메시지를 절대 처리할 수 없는 시스템은 아닙니다. producer의 max.request.size, topic의 max.message.bytes, consumer의 max.partition.fetch.bytes, broker의 replication 관련 fetch limit 등을 맞추면 기본 제한보다 큰 record batch를 통과시킬 수 있습니다.
하지만 대용량 메시지 테스트는 disk를 아주 빠르게 먹습니다.
예를 들어 100 MiB 메시지를 초당 10개씩 10분 동안 넣는 테스트를 생각해봅시다.
100 MiB x 10 messages/sec x 600 sec = 약 586 GiB
replication factor 3 적용 = 약 1.7 TiB
여기에 compression ratio가 기대보다 낮거나, producer retry로 중복 write가 생기거나, 여러 consumer group이 downstream storage에 다시 저장하거나, 테스트 topic을 지우지 않고 retention을 길게 둔다면 실제 부담은 더 커집니다.
이때 RetentionSizeInPercent가 낮게 보일 수도 있습니다. 테스트 topic의 retention.bytes를 크게 잡았거나 unlimited로 두었기 때문입니다. 하지만 log.dirs의 물리 free space는 이미 빠르게 줄고 있을 수 있습니다.
대용량 메시지 테스트에서 자주 나오는 실수는 이런 형태입니다.
- message size limit만 올리고 disk budget을 다시 계산하지 않습니다.
- replication factor를 곱하지 않습니다.
- 테스트 topic retention을 운영 topic과 같은 값으로 둡니다.
- 테스트 후 topic delete나 retention 축소를 잊습니다.
- broker별 partition 배치를 보지 않고 cluster 총량만 봅니다.
du나df를 테스트 후에 한 번만 봅니다.- consumer가 느려지면 producer만 멈추고 broker에 쌓인 log는 그대로 둡니다.
이런 테스트는 “애플리케이션이 큰 메시지를 보낼 수 있는가”를 확인하려다가 “Kafka broker의 disk를 얼마나 빨리 채울 수 있는가”를 같이 실험하게 됩니다.
테스트 전 체크리스트
대용량 메시지 테스트를 해야 한다면, 시작 전에 disk 계산을 먼저 하는 편이 안전합니다.
expected broker storage
~= message_size
x message_count
x replication_factor
x retention_window_overlap
x retry_or_duplicate_factor
x overhead_margin
정확한 공식은 아닙니다. 하지만 이 계산을 해보면 “이번 테스트가 broker disk를 채울 수 있는 크기인지” 감이 옵니다.
운영 체크리스트는 더 실무적으로 잡는 것이 좋습니다.
- 테스트 topic을 별도로 만듭니다.
- 테스트 topic에는 짧은
retention.ms나 작은retention.bytes를 둡니다. - 테스트 중
log.dirs별 free bytes를 실시간으로 봅니다. - broker별 partition 배치와 leader 분포를 확인합니다.
- 테스트 중단 조건을 정합니다. 예를 들어 any log.dir free space가 20% 미만이면 즉시 중단합니다.
- 테스트 후 topic delete 또는 retention 축소 절차를 미리 정합니다.
- cleanup이 실제 free space 회복으로 이어졌는지
df로 확인합니다.
가능하다면 운영 cluster와 분리된 cluster에서 테스트해야 합니다. 분리가 어렵다면 최소한 별도 topic, 짧은 retention, producer quota, 명확한 중단 조건은 있어야 합니다.
모니터링은 세 층으로 나눠야 한다
Kafka storage monitoring은 한 metric으로 끝내기 어렵습니다.
세 층으로 나눠보면 덜 헷갈립니다.
1. partition retention pressure
- RetentionSizeInPercent
- LocalRetentionSizeInPercent
- Log Size
2. broker/log.dir physical pressure
- filesystem available bytes
- filesystem used percent
- write latency
- consumption rate to zero
3. Kafka symptom
- produce latency
- under-replicated partitions
- ISR shrink
- reassignment lag
- LogDirectoryOffline
첫 번째 층은 topic owner에게 좋습니다. 두 번째 층은 platform operator에게 중요합니다. 세 번째 층은 이미 문제가 사용자 경험에 가까워졌다는 신호입니다.
좋은 알람은 이 셋을 섞어 읽습니다.
RetentionSizeInPercent가 높다:
topic retention 정책을 점검한다.
log.dir free space가 낮다:
broker 생존 여유를 확보한다.
둘 다 나쁘다:
retention cleanup, partition 이동, producer throttle, test 중단을 같이 검토한다.
Kafka를 이해할 때는 broker, topic, partition, consumer group을 코드 개념으로만 보지 않고 운영 신호로도 읽어야 합니다. Konduo는 Kafka 같은 클러스터형 리소스를 플러그인으로 연결해 상태, 메트릭 근거, 진단, 알림 대응을 하나의 운영 흐름에서 확인할 수 있도록 합니다. 이 글의 주제처럼 Kafka partition metric과 host filesystem metric을 함께 읽어야 하는 경우에는 리소스 경계를 넘는 운영 문맥이 특히 중요해집니다.
정리
Kafka 4.3의 Partition Size Percentage metrics는 반가운 개선입니다. 이제 partition이 retention 한도에 얼마나 가까운지 훨씬 직접적으로 볼 수 있습니다. 특히 retention.bytes가 topic마다 다르고, tiered storage에서 local retention과 remote retention을 나눠 봐야 하는 환경에서는 좋은 신호입니다.
하지만 이 메트릭은 log.dirs free space metric이 아닙니다.
운영 판단은 이렇게 나눠야 합니다.
RetentionSizeInPercent:
partition이 retention 한도에 가까운가?
Filesystem free space:
broker가 지금 계속 쓸 물리 공간이 남아 있는가?
대용량 메시지 테스트에서는 이 차이가 더 중요합니다. 큰 메시지는 설정만 맞추면 통과할 수 있지만, 통과한 byte는 broker log, replica, downstream storage, retry path 어딘가에 실제로 남습니다. 테스트는 항상 disk budget을 함께 검증해야 합니다.
Kafka storage monitoring에서 percentage metric은 좋은 지도입니다. 하지만 broker를 살리는 것은 결국 log.dirs의 실제 남은 공간입니다. 그래서 물리 free space는 Kafka 운영에서 반드시 직접 관리해야 하는 1급 지표로 두어야 합니다.
함께 읽기 좋은 글
이 글의 관점과 이어지는 주제를 더 보려면 아래 글도 함께 읽어볼 수 있습니다.
- Kafka가 잘하는 대용량과 보내면 안 되는 대용량 - 대용량 파일 payload가 Kafka와 downstream storage에서 어떻게 증폭되는지 다룹니다.
- Kafka 브로커의 병목은 항상 Kafka 안에 있지 않다 - Kafka 증상을 OS와 storage path까지 따라가며 분석한 경험을 다룹니다.
- JVM 메트릭만으로는 컨테이너를 설명할 수 없다 - JVM 밖의 cgroup, filesystem, fd, I/O 신호를 함께 봐야 하는 이유를 다룹니다.