문제
1분에 약 5만건 정도 메세지 발생하여
총 Lag 150만개 발생하여 처리 지연 발생
Lag 이란? 컨슈머가 마지막으로 읽은 offset과 Producer가 마지막으로 넣은 offset의 차이
원인
Produce가 보내는 데이터양에 비해 Consumer 처리량 작음
따라서 Consumer 처리량을 높이는 것이 목표
조치 사항 #1
컨슈머와 파티션의 개수를 동일하게 1:1 매핑 되도록 조절
![]() |
![]() |
의문점
공식문서에선 아래 설정을 조절하라는 설명뿐..
- fetch.max.bytes (50mb) : 모든 파티션에서 한번의 fetch로 가져오는 총 데이터 개수
- max.partition.fetch.bytes(1mb) : 하나의 파티션에서 한번의 fetch로 가져오는 총 데이터 개수
한번의 fetch로 가져오는 메세지 양 계산
현재 서비스에서 message는 1개당 412 bytes다.
- 한번의 fetch로 가져오는 총 개수는 127254개다. (50mb * 1024 * 1024 / 412 bytes = 127254개)
- 한 파티션에서 한번의 fetch로 가져오는 총 개수는 2545개 (1mb * 1024 * 1024 / 412 bytes = 2545개)
현재 인스턴스는 3개이므로 3초(idle.between.polls)마다 약 7500개 처리가 되므로, 1분에 15만개 처리가 되야한다.
의문점
1분에 15만개의 처리능력을 가지고 있고, 1분에 5만개의 message가 생성되는데 왜 처리 지연이 발생하지?
하지만 인스턴스를 단순히 늘리는것이 아닌
근본적인 병목 현상을 발견하고 해결할 수 없을까?
Kafka 내부 구현에 대한 이해가 필요했음
Consumer 시퀀스 다이어그램
consumer 주요 동작 3단계 (반복)
(#1) idle.between.poll.ms 만큼 대기 상태
- 3초마다 처리해야하는 비즈니스 요구사항에 의해 3초 대기
(#2) poll() 요청 : completedFetches 라는 큐에서 max.poll.records(= 500)만큼 레코드 조회
- 만약 처리할 레코드가 있다면 바로 리스너 호출
(#3) fetch() 요청 : 최대 fetch.max.bytes(= 50mb) 만큼 레코드를 조회해서 completedFetch 큐에 넣음
- 현재 서비스에서 message는 1개당 206 character로 412 bytes다.
- 즉 한번의 fetch로 가져오는 개수는 127254개다. (50mb * 1024 * 1024 / 412 bytes = 127254개)
조치 사항 #2
아래의 설정으로 재조정
- max.poll.records = 5000 (한번의 poll()로 가져오는 사이즈)
- max.partition.fetch.bytes = 2mb (한번의 fetch()로 파티션마다 가져오는 최대 사이즈가 약 5000개가 되도록)
기존대비 처리량 10배 증가
- 기존 처리량 : 토픽마다 분당 1만개 처리
- 개선된 처리량 : 토픽마다 분당 10만개 처리
max.poll.records 추가 고려 사항
- max.poll.interval.ms (= 5분)내에 poll()을 호출하지 않으면 해당 컨슈머에 문제가 생겼다고 간주하여 리밸런싱이 일어난다.
- 따라서 실제 테스트를 진행하며 문제 없는지 파악하고 5000개로 적용함.
배운점
1. kafka Consumer 내부 구현 및 동작
2. Kafka 내부 구현 이해를 통해서 Kafka 관련 모든 문제에 대한 해결 능력
3. 더 나아가 다른 오픈소스도 병목 구간을 탐색할 수 있다는 자신감