ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • kafka retention 용량 설정 값 이해하기
    Programming 2023. 5. 1. 01:17

    overview

    • retention.bytes옵션을 통해 retention 용량을 1GB로 설정했었는데 토픽의 용량이 7GB가 넘어가는 것들이 생겼다.
    • 브로커당 용량이라고 이해해도 3GB넘지 않을 것이고 리플리케이션 팩터가 2라서라기엔 2GB를 훌쩍넘는다. 7GB라니...오버에도 한참 오버했다. 도대체 이 설정값들은 각각 무엇을 의미하는 것이고 어떤 매커니즘으로 메세지들이 지워지는지 파악해보자

    Topic

    • retention 용량 설정에 대해서 알아보기 전에 토픽에 대해서 간단히 정리해보자

    partitions

    • 리더 파티션과 팔로워 파티션으로 구분(replication-factor가 1인 경우 리더 파티션만 존재)
    • 리더 파티션은 프로듀서 또는 컨슈머와 직접 통신하는 파티션으로 읽기, 쓰기 연산을 담당
    • 팔로워 파티션은 리더 파티션의 데이터를 복사하여 보관하는 역할, 장애 발생시 리더 파티션의 지위를 가지게 되는 예비용 파티션
    • 파티션이 많아지면 그만큼 파일 핸들로도 늘어나게 되어서 파티션이 많다고 무조건 좋지는 않음
    • 카프카에서는 브로커당 약 2천개 정도의 최대 파티션 수를 권장

    replication-factor

    • 기본값 replication factor=1 → 복제가 없는 경우 리더 파티션만 존재
    • broker 숫자만큼 설정 가능
    • 파티션과 리플레케이션 팩터 모두 늘릴 수만 있고 줄일 수는 없어서 신중하게 선택해야함

    ISR(In Sync Replica)

    • ISR이라는 논리적인 그룹에 리더와 팔로워가 묶여있으며 ISR 그룹에 속하지 못한 팔로워는 새로운 리더가 될 수 있는 자격이 없음
    • 현재 리플리케이션되고 있는 리플리케이션 그룹을 뜻함

    retention

    • retention은 기간과 용량을 설정해줄 수 있다.
    • or조건으로 기간이 만료되었거나 용량이 초과되면 설정한 기간만큼 메세지를 지우거나 용량만큼 메세지를 지운다.
    • 토픽의 메세지들은 파티션으로 나뉘며, 각 파티션들은 세그먼트로 분류할 수 있다.
    • log.dirs의 디렉토리를 확인해보면 생성한 파티션을 확인할 수 있다
    |── my-topic-0
       ├── 00000000000000000000.index
       ├── 00000000000000000000.log
       ├── 00000000000000000000.timeindex
       ├── 00000000000000001007.index
       ├── 00000000000000001007.log
       ├── 00000000000000001007.snapshot
       ├── 00000000000000001007.timeindex
       ├── leader-epoch-checkpoint
    • 세그먼트는 다시 log, index, timeindex, snapshot, leader-epoch-checkpoint로 나뉘게된다.
      • log file - 실제 record들이 기록되는 곳.
      • index file - 파티션의 논리적인 인덱스와 파일의 물리적인 인덱스를 매핑해주는 파일
      • snapshot file - 중복저장을 피하기 위해서 사용하는 sequence ID들에 대해서 프로듀서의 상태들이 담겨있다.
      • leader-epoch-checkpoint - 컨트롤러에 의해 이전에 할당된 리더들의 숫자를 참고한다. 레플리카들은 leader epoch를 최근의 리더를 확인하는데 사용한다.
    파라미터 명 기본 값 효과
    log.segment.bytes 1 GiB segment 단일 로그 파일의 용량 제한
    log.index.size.max.bytes 10485760 (10MB) 오프셋 인덱스의 총 용량
    log.retention.bytes -1 (지우지 않음) 로그 파일의 총 용량
    log.retention.ms/ log.retention.minutes/ log.retention.hours null//null/168(hours) log파일을 저장할 주기
    log.retention.check.interval.ms 300000 (5분) 로그를 삭제할 대상을 확인하는 시간 주기
    log.segment.delete.delay.ms 60000 (1분) 파일을 파일시스템으로 지우기 전에 기다리는 시간의 양

    segment.bytes

    • 단일 로그 파일의 용량

    retention.bytes

    • 로그 파일들의 총 용량
    • log.retention.check.interval.ms은 기본 값이 5분이다. 만약 설정한 log.retension값이 이 값보다 짧으면 원하는 시간주기대로 log를 삭제하지 못할 수 있다.
      • 한마디로 log.retention.check.interval.ms값보다 log.retension값이 더 커야한다.
    • segment.bytes는 각 log파일들의 용량을, retention.bytes는 각 log파일들이 합쳐진 총 용량을 의미한다.
      • 예를들어 segment.bytes는 10mb, retention.bytes는 20mb로 설정하면 10mb짜리 log파일이 2개 생성된다.
      • segment.bytes보다 retention.bytes가 값이 더 커야지 적용된다.

    • 다만 이 설정은 active중인 segment에 대해서는 해당되지 않는다. active중인 segment가 segment.bytes에 설정한 만큼을 달성하면 retention.bytes에 설정한 만큼 가장 오래전에 생성된 segment먼저 지워지게 된다.

    Proof

    • partitions가 1, replication-factor가 1이고 segment.bytes가 5MB, retention.bytes가 10MB인 토픽 하나를 생성한다.
    @kafka:/$ kafka-topics.sh --bootstrap-server localhost:9092 \
     --create --topic test_topic1 --partitions 1 --replication-factor 1 -add-config segement.bytes=5242880,retention.bytes=10485760
    test_topic1-0$ du -h *
    0	00000000000000000000.index
    0	00000000000000000000.log
    0	00000000000000000000.timeindex
    4.0K	leader-epoch-checkpoint
    4.0K	partition.metadata
    • 0kb로 log파일이 제대로 생성된 것을 확인할 수 있다. 이제 00000000000000000000.log 파일은 액티브 세그먼트로써 실시간으로 메세지들이 5MB까지 저장될 것이다.
    • test 메세지를 적재하기 위해 kafka-python 클라이언트를 받아서 임의의 메세지를 생성한다.
    !pip install kafka-python
    
    from kafka import KafkaProducer
    from json import dumps
    
    producer = KafkaProducer(acks=0, compression_type='gzip',
                             bootstrap_servers=['localhost:9092'],
                             value_serializer=lambda x: dumps(x).encode('utf-8'))
                             
    counter=0
    while True:
        producer.send('test_topic1', value={'test_key': f"test_value {counter}"})
        counter+=1
        producer.flush()
    • (주의)while문으로 중지하기 전까지 계속해서 메세지를 생성하므로 데이터 확인이 끝나면 반드시 프로세스를 종료시켜 준다.
    test_topic1-0$ du -h *
    12K	00000000000000000000.index
    5.0M	00000000000000000000.log
    16K	00000000000000000000.timeindex
    12K	00000000000000052539.index
    5.0M	00000000000000052539.log
    4.0K	00000000000000052539.snapshot
    16K	00000000000000052539.timeindex
    4.0K	00000000000000104918.index
    1.4M	00000000000000104918.log
    4.0K	00000000000000104918.snapshot
    8.0K	00000000000000104918.timeindex
    4.0K	leader-epoch-checkpoint
    4.0K	partition.metadata
    • segment.bytes에서 설정한대로 단일 로그 파일의 용량이 5MB로 2개 총 10MB의 segment가 완성되었다. 그런데 지금은 10MB를 넘어서 하나의 로그파일이 더 생성되고 11.4M가 되었다.
    • 앞서 언급한 것처럼 1.4MB짜리 로그파일은 액티브 segment이며 이 파일의 용량이 5MB으로 채워지게 되면 가장 처음에 생성되었던 00000000000000000000.log부터 차례대로 지워지게 된다.
    • 확인을 위해서 계속해서 데이터를 넣어보자
    test_topic1-0$ du -h *
    12K	00000000000000000000.index
    5.0M	00000000000000000000.log
    16K	00000000000000000000.timeindex
    12K	00000000000000052539.index
    5.0M	00000000000000052539.log
    4.0K	00000000000000052539.snapshot
    16K	00000000000000052539.timeindex
    12K	00000000000000104918.index
    5.0M	00000000000000104918.log
    4.0K	00000000000000104918.snapshot
    16K	00000000000000104918.timeindex
    4.0K	00000000000000157316.index
    892K	00000000000000157316.log
    4.0K	00000000000000157316.snapshot
    4.0K	00000000000000157316.timeindex
    4.0K	leader-epoch-checkpoint
    4.0K	partition.metadata
    • active segment가 00000000000000104918.log에서 00000000000000157316.log으로 바뀌었다.
    test_topic1-0$ du -h *
    12K	00000000000000000000.index.deleted
    5.0M	00000000000000000000.log.deleted
    16K	00000000000000000000.timeindex.deleted
    12K	00000000000000052539.index
    5.0M	00000000000000052539.log
    4.0K	00000000000000052539.snapshot
    16K	00000000000000052539.timeindex
    12K	00000000000000104918.index
    5.0M	00000000000000104918.log
    4.0K	00000000000000104918.snapshot
    16K	00000000000000104918.timeindex
    4.0K	00000000000000157316.index
    892K	00000000000000157316.log
    4.0K	00000000000000157316.snapshot
    4.0K	00000000000000157316.timeindex
    4.0K	leader-epoch-checkpoint
    4.0K	partition.metadata
    • 예상했던 것처럼 가장 처음에 생성된 00000000000000000000.log가 deleted상태로 바뀌게 되고 segment.delete.delay.ms의 기본값인 1분 뒤에 완전히 지워지게 된다.
    test_topic1-0$ du -h *
    12K	00000000000000052539.index
    5.0M	00000000000000052539.log
    4.0K	00000000000000052539.snapshot
    16K	00000000000000052539.timeindex
    12K	00000000000000104918.index
    5.0M	00000000000000104918.log
    4.0K	00000000000000104918.snapshot
    16K	00000000000000104918.timeindex
    4.0K	00000000000000157316.index
    892K	00000000000000157316.log
    4.0K	00000000000000157316.snapshot
    4.0K	00000000000000157316.timeindex
    4.0K	leader-epoch-checkpoint
    4.0K	partition.metadata

    Conclusions

    • 액티브 세그먼트까지 포함해서 파티션당 순간적으로 최대 retention.bytes + segment.bytes만큼의 용량이 추가로 필요하다.
    • 용량이 7GB까지 늘어있던 토픽은 파티션이 2, 레플리케이션 팩터가 2 였다.
    • 0번파티션은 0번, 1번 브로커에 레플리케이티드 되어있고, 1번 파티션은 각각 0번과 2번에 레플리케이티드 되어있다.
    • segment.bytes는 1기가, retention.bytes도 1기가로 설정되어있으므로 액티브 세그먼트를 고려하면 각 브로커의 파티션당 세그먼트 파일들이 순간적으로 최대 2GB까지 늘어날 수 있다.
    • 따라서 레플리케이션 되어있는 총 개수를 곱하면 해당 토픽은 순간적으로 최대 8GB까지 늘어날 수 있다. 따라서 7GB라는 용량은 충분히 정상적인 값이다.

    reference

    https://www.conduktor.io/blog/understanding-kafkas-internal-storage-and-log-retention/

     

    Understanding Kafka's Internal Storage and Log Retention

    Apache Kafka is a commit-log system. Understanding configuration parameters gives you a lot more control over how you handle your data.

    www.conduktor.io

     

    댓글

Copyright 2023. 은유 All rights reserved.