2025년 11월 3일 작성
Kafka Page Cache - OS를 활용한 고성능 I/O
Kafka는 OS의 page cache를 활용하고 sequential I/O, zero-copy 등의 최적화 기법으로 disk 기반임에도 높은 throughput을 유지합니다.
Kafka의 고성능 I/O 전략
- Kafka는 disk 기반 저장소임에도 높은 throughput과 낮은 latency를 유지합니다.
- page cache, sequential I/O, zero-copy, batch processing 등 OS level의 최적화를 적극 활용하기 때문입니다.
- application level cache 대신 OS의 page cache를 활용하여 memory를 효율적으로 사용합니다.
Page Cache 활용
- page cache는 OS가 disk I/O 성능을 향상시키기 위해 관리하는 memory caching mechanism입니다.
- OS는 최근에 읽거나 쓴 disk block을 memory에 caching합니다.
- 동일한 data에 대한 반복 접근 시 disk I/O 없이 memory에서 직접 읽습니다.
- Kafka는 자체 application cache를 구현하지 않고 OS의 page cache에 의존합니다.
- message를 disk에 쓸 때, 실제로는 OS의 page cache에 먼저 기록됩니다.
- OS가 적절한 시점에 page cache의 내용을 disk에 flush합니다.
- consumer가 message를 읽을 때도 page cache에서 직접 읽는 경우가 많습니다.
- page cache를 활용하면 JVM의 memory 관리 부담을 OS에 위임할 수 있습니다.
- memory 효율성 : JVM heap 대신 OS page cache를 사용하여 garbage collection overhead를 피합니다.
- warm cache 유지 : process 재시작 후에도 OS page cache는 유지되어 성능 저하가 최소화됩니다.
- 자동 관리 : OS가 자동으로 memory를 관리하므로 tuning이 간단합니다.
- producer와 consumer의 처리 속도가 비슷하면, message가 page cache에 머물러 disk I/O가 거의 발생하지 않습니다.
- Kafka가 실시간 streaming에 최적화된 이유 중 하나입니다.
Sequential I/O 최적화
- Kafka는 sequential I/O pattern을 사용하여 disk 성능을 극대화합니다.
- message는 partition의 끝에 순차적으로 append됩니다.
- consumer는 offset 순서대로 순차적으로 읽습니다.
- sequential I/O는 random I/O에 비해 훨씬 빠릅니다.
- modern disk(HDD)는 sequential read/write 시 100MB/s 이상의 성능을 보입니다.
- random I/O는 seek time으로 인해 수백 KB/s 수준으로 느려집니다.
- SSD의 경우에도 sequential I/O가 더 빠르고 수명이 연장됩니다.
- sequential I/O는 OS의 read-ahead와 write-behind 최적화를 극대화합니다.
- read-ahead : OS가 sequential read pattern을 감지하고 미리 다음 block을 page cache에 load합니다.
- write-behind : OS가 여러 write를 batch로 묶어 한 번에 disk에 기록합니다.
- Kafka의 log segment file 구조는 sequential I/O를 자연스럽게 지원합니다.
- append-only log 구조로 항상 file의 끝에 쓰기가 발생합니다.
- retention policy에 따라 오래된 segment file 전체를 삭제합니다.
Zero-Copy 최적화
-
zero-copy는 data를 kernel space에서 user space로 복사하지 않고 직접 network로 전송하는 기법입니다.
- 일반적인 data 전송 과정(zero-copy 미사용)은 4단계로 이루어집니다.
- disk에서 OS buffer로 data 읽기 (kernel space).
- OS buffer에서 application buffer로 복사 (kernel -> user space).
- application buffer에서 socket buffer로 복사 (user -> kernel space).
- socket buffer에서 network로 전송 (kernel space).
- zero-copy를 사용하면 과정이 단순해집니다.
- disk에서 OS buffer로 data 읽기 (kernel space).
- OS buffer에서 socket buffer로 직접 전송 (kernel space 내에서만).
- socket buffer에서 network로 전송.
- Kafka는
sendfile()system call을 사용하여 zero-copy를 구현합니다.- Java NIO의
FileChannel.transferTo()method를 통해 사용합니다. - CPU overhead와 memory copy를 대폭 줄여 성능을 향상시킵니다.
- Java NIO의
- zero-copy는 특히 consumer가 message를 읽을 때 큰 효과를 발휘합니다.
- page cache의 data를 직접 network socket으로 전송합니다.
- 수천 개의 consumer에게 동일한 message를 전송할 때도 효율적입니다.
Batch Processing
-
Kafka는 개별 message가 아닌 batch 단위로 처리하여 효율성을 높입니다.
- producer batching : 여러 message를 하나의 batch로 묶어 broker에게 전송합니다.
batch.size와linger.ms설정을 통해 batch 크기와 대기 시간을 조절합니다.- network round trip 횟수를 줄여 throughput을 향상시킵니다.
- broker batching : broker는 수신한 batch를 그대로 disk에 기록합니다.
- 개별 message를 parsing하지 않고 batch 전체를 처리하여 CPU overhead를 줄입니다.
- consumer batching : consumer는 한 번의 fetch request로 여러 message를 가져옵니다.
fetch.min.bytes와fetch.max.wait.ms설정으로 fetch 동작을 조절합니다.- network overhead를 줄이고 처리 효율을 높입니다.
- batch processing은 network, disk, compression 모든 계층에서 효율을 높입니다.
- network overhead 감소 (packet 수 감소).
- disk I/O 효율 향상 (larger sequential write).
- compression 효율 증가 (larger batch일수록 압축률 향상).
Data Compression
-
Kafka는 message compression을 지원하여 network와 storage 사용량을 줄입니다.
- 다양한 compression algorithm을 지원합니다.
- gzip : 높은 압축률이지만 CPU 사용량이 높습니다.
- snappy : 균형잡힌 압축률과 속도로 기본 권장됩니다.
- lz4 : 매우 빠른 압축/해제 속도와 낮은 CPU 사용량입니다.
- zstd : 높은 압축률과 빠른 속도의 균형이 좋습니다.
- producer에서
compression.type설정으로 compression을 활성화합니다.- batch 단위로 압축되므로 batch 크기가 클수록 압축 효율이 높습니다.
- 압축된 batch는 broker와 consumer 간 전송 시에도 압축 상태를 유지합니다.
- broker는 압축된 message를 그대로 저장하고 전송합니다.
- broker가 압축을 해제하지 않으므로 CPU overhead가 없습니다.
- consumer가 최종적으로 압축을 해제하여 message를 처리합니다.
- compression은 network와 storage 양쪽의 사용량을 줄여줍니다.
- network bandwidth 절약 (특히 WAN 환경에서 유용).
- disk storage 절약.
- 더 많은 message를 batch에 포함 가능.
Memory Mapped Files (mmap)
-
Kafka는 index file 접근 시 memory mapped file(mmap)을 사용합니다.
- mmap은 file을 process의 address space에 직접 mapping하는 기법입니다.
- file read/write가 memory access처럼 동작합니다.
- OS가 자동으로 page cache를 통해 caching합니다.
- Kafka는 offset index와 time index file에 mmap을 사용합니다.
- consumer가 특정 offset의 message를 찾을 때 index file을 빠르게 검색합니다.
- binary search를 통해 효율적으로 원하는 위치를 찾습니다.
- mmap은 file을 memory처럼 접근하게 하여 I/O 처리를 단순화합니다.
- file I/O overhead가 감소합니다.
- OS가 자동으로 page cache를 관리합니다.
- file I/O API가 불필요하여 code가 간결해집니다.
Kafka 성능 최적화 Best Practice
- batch size를 적절히 설정해야 합니다.
batch.size=16384(16KB, producer 기본값).linger.ms=10-100(throughput 우선 시).
- compression을 활성화하여 성능을 향상시킵니다.
compression.type=snappy또는lz4(균형잡힌 선택).compression.type=zstd(높은 압축률 필요 시).
- 충분한 OS page cache를 확보해야 합니다.
- JVM heap은 작게 (6-8GB 권장).
- 나머지 memory는 OS page cache에 할당.
- partition 수를 적절히 설정해야 합니다.
- consumer 병렬성을 고려하여 설정.
- 너무 많은 partition은 metadata overhead 증가.
- retention 정책을 적절히 설정해야 합니다.
log.retention.hours또는log.retention.bytes.- 불필요한 data를 빠르게 삭제하여 disk 공간 확보.
Reference
- https://kafka.apache.org/documentation/#design
- https://www.confluent.io/blog/configure-kafka-to-minimize-latency/
- https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines