일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 자바
- 백준
- 이스티오
- gradle
- 스트림
- redis
- 보조스트림
- K8s
- 쿠버네티스
- 토비의 스프링 정리
- GC
- spring
- SpringBoot
- OS
- IntellJ
- 스프링
- jvm
- 토비의 스프링
- Java
- Stream
- Real MySQL
- JPA
- Stack
- mysql
- Kotlin
- Collection
- list
- 자바 ORM 표준 JPA 프로그래밍
- thread
- MSA
- Today
- Total
인생을 코딩하다.
[Kafka] 카프카 메시지 중복 컨슘, 누락이 발생할 수 있는 경우 본문
카프카를 사용시 consume이 단 한 번만 일어나면 좋겠지만 실제로 그렇지 않은 경우가 종종 있습니다.
consume이 딱 한 번만 일어나지 않으면 어떤 문제가 발생할까요?
- consumer가 카프카 브로커로부터 메시지를 가져와서 데이터 처리를 할 텐데, 만일 중복 consume이 발생하면 그 데이터 처리도 중복으로 처리될 수 있습니다.
- 때로는 consume 누락이 발생할 수도 있습니다. 그럼 데이터 처리도 누락됩니다.
이 문제를 막기 어려운 근본적인 이유는 아래와 같습니다.
- commit 시점과 데이터 처리 완료 시점이 완벽하게 일치할 수 없는 경우(그 시간 간극 동안 리밸런싱이 발생할 수도 있음)
- offset 관리가 consumer측이 아니라 broker 측에서 이루어지는 경우(_consumer_offsets 토픽)
- 개발자 자의에 의해 offset reset을 해서 다시 consume할 일이 있는 경우
그럼 누락이 발생하는 경우부터 알아보도록 하겠습니다.
자동커밋(Auto comit) - 누락 발생
* 주기 : auto.commit.interval.ms
fetch 후에
- 데이터를 처리하는 쪽에서는 101번, 102번 까지 데이터를 처리
- commit 103번까지 완료
인 상황에서 Rebalnce가 시작되었다면 컨슈머와 파티션 간의 관계는 끊어지고 다시 새로운 관계를 만들게 됩니다. 그럼 broker의 기록을 기준으로 message consume이 다시 시작되게 됩니다. 이 경우 broker 입장에서는 103번 부터는 데이터 처리가 되었다고 보기 때문에 message consume는 104번부터 다시 fetch 되게 됩니다.
따라서 데이터를 처리하는 쪽에서도 103번 message는 pass하고 104번부터 처리하게 됩니다.
그럼 이제 중복 컨슘이 발생하는 경우를 알아보도록 하곘습니다.
자동커밋(Auto comit) - 중복 발생
fetch 후에
데이터를 처리하는 쪽에서는 102번까지 처리한 상황입니다.
하지만 아직 commit하지 않았는데 갑자기 Rebalnce가 발생하여 broker측에서는 100번까지만 commit된 것으로 기록합니다. 그리고 파티션과 컨슈머의 관계가 재형성됩니다.
이 경우에 브로커는 100번까지만 커밋했으니 101번부터 메시지를 다시 가져가라고 하기 때문에 데이터를 처리하는 쪽에서 101, 102번 데이터를 한 번더 처리하게 됩니다. 이 경우에 중복 컨슘이 발생할 수 있습니다.
수동 커밋도 마찬가지 입니다.
수동커밋(Auto comit) - 중복 발생
수동 커밋은 보통 데이터를 다 처리한 뒤에 커밋하게 됩니다. 하지만 커밋을 하기전에 리밸런싱이 발생하면 자동 커밋처럼 똑같이 중복이 발생할 수도 있습니다. 따라서 수동 커밋은 데이터 처리 타이밍과 커밋 타이밍을 개발자가 원하는 데로 조절할 수 있지만 그 시점을 완전히 일치 시킬 수는 없습니다. 이러한 근본적인 문제는 해결할 수가 없습니다.
결국에는 Rebalncing이 문제
지금까지의 경우를 살펴보았을때 Rebalncing이 문제인 것을 알수가 있습니다. Rebalncing이 자주 발생하면 여러가지 문제가 될 수 있습니다.
- Rebalncing이 발생하면 중복 Consume 혹은 Consume 누락 가능성이 발생하는 타이밍이 생깁니다.
- 심지어, Rebalncing이 발생하는 동안 Consume이 멈추기 때문에 성능상 문제도 발생합니다.
Rebalncing은 언제 생기는건데?
- 파티션이 추가 되거나 리어사인이 되서 서로 관계를 바꿔야 하는 경우 (broker의 변화)
- 컨슈머그룹 내 컨슈머가 추가되거나 제거된 경우 (컨슈머 측의 변화)
이 경우 좀 더 유심히 봐야할 건 컨슈머 측의 변화입니다. 컨슈머 측에서 능동적인 변화가 발생한 경우가 아니더라도 컨슈머 측의 변화중에서는 비정상 적인 변화의 경우도 존재합니다.
session.timeout.ms와 heatbeat.interval.ms
- heartbeat(consumer이 정상인지 주기적으로 보내는 신호)가 한동안 broker쪽으로 오지 않아서 결국 timeout이 발생하면 broker쪽에서는 consumer 상태 비정상인 것으로 판단합니다.
- 따라서 보통은 session.timeout.ms 대비 heatbeat.interval.ms을 짧게(3분의 1 정도) 가져갑니다. 이렇게 성정하면 heartbeat를 두 번 정도 보내지 않아도 한 번정도 기회가 남기 때문입니다.
max.poll.interval.ms
- consumer쪽에서 poll을 한동한 해가지 않으면 consumer 상태를 비정상으로 판단합니다.
- consumer에서는 매번 건건이 시간이 오래 걸리는 로직을 수행하서는 안됩니다. 안그러면 consumer가 poll을 하지 못해서 max.poll.interval.ms를 넘겨버리고 계속 중단되는 상황이 발생하기 때문입니다.
- 또한 중단되는 경우에 conumser에 lag이 계속 쌓이는 상황도 발생합니다.
정리
사실 consume 중복 및 누락은 consumer만의 입장입니다.
- 위 그림 및 설명들을 다시 생각해보면 commit 실제로 한 번만 발생합니다. 즉, 단 한번만 레코드를 다루고 있습니다. 결국 comiit을 하는 건 broker 쪽이고 그리고 이것을 consume하는 건 결국 consumer 쪽입니다.
consume 중복 및 누락을 대비하기 위해서는
- Rebalncing을 줄일 수 있게 옵션 값을 잘 설정해야 합니다.
- 자동 커밋으로 설정할지 수동 커밋으로 설정할지는 고려해봐야 합니다.
- 일반적으로 중복이 누락보다는 낫다고 생각합니다. 중복 같은 경우는 해결할 수 있는 여러 대안(redis, outbox pattern 등)들이 존재하지만 유실 같은 경우는 해결할 수 있는 방법이 없습니다. 따라서 유실을 해결할 수 없는 자동 커밋보다는 유실을 사전에 방지하고 중복을 해결할 수 있는 방향인 수동 커밋을 사용하는게 나을 것 같다고 생각합니다. (유실의 경우도 outbox pattern으로 해결 가능할 것 같긴 하네요)
- 하지만 어느 정도의 누락은 별로 상관없을 수도 있습니다. 예를들어 로그 데이터 같은 경우 전체적인 통계에 큰 영향을 미치지 않을 수도 있기 때문입니다.
- 따라서 상황에 따라 적절한 설정이 필요하다고 생각됩니다.
'Kafka' 카테고리의 다른 글
[Kafka] 컨슈머 장애로 인한 토픽<->컨슈머 자동 리밸런싱전, 컨슈머에 장애가 생긴걸 어떻게 판단하여 자동 리밸런싱이 되게 할 수 있을까 (2) | 2023.02.26 |
---|---|
Apache Kafka는 어떤 방식으로 동작할까? (0) | 2021.10.20 |