kafka auto commit의 위험성
개요
kafka auto commit에 대해 명확히 이해하고 kafka auto commit을 활용했을 때 위험성에 대해 알아보고자 합니다.
auto commit이란?
kafka poll()을 통해 가져온 레코드를 어디까지 읽었는지 자동으로 commit 할 수 있는 옵션인 auto.commit을 제공합니다.
enable.auto.commit = true
enable.auto.commit = trueauto.commit.interval.ms = 100ms
위의 설정은 100ms 시간의 간격마다 auto commit을 수행한다는 것을 의미 합니다.
뭔가 자동으로 해준다? 편리하게 사용할 수 있을 것 같은 느낌듭니다.
예를 들어 poll()을 통해 500개의 레코드를 가져옵니다.
100ms가 지났을 때는 100개의 레코드를 처리했다고 가정했을 때 나머지 400건의 레코드는 아직 처리되지 않았지만 이미 commit이 되었고 kafka입장에서는 500개의 레코드가 정상적으로 처리되었다고 판단할 것입니다.
어떤 것이 위험할까?
레코드의 유실 및 중복처리가 발생할 수 있습니다.
레코드가 유실되는 케이스먼저 소개해보겠습니다.
poll() 메서드를 호출하여 데이터를 가지고 간 이후 commit을 수행하고 consumer에서 장애가 발생하면 어떻게 될까요?
예를 들어 100건의 레코드만 읽은 뒤 장애가 발생했다면 400건의 레코드는 유실될 수 있습니다.
만약 spring-kafka를 활용한다면 poll() 메서드가 호출될 때 commit이 발생하므로 유실되지 않습니다.
자세한 내용은 아래글을 참고해주세요.
spring kakfa auto-commit 동작원리: 데이터 유실과 중복처리
레코드가 중복처리될 수도 있습니다.
poll() 메서드를 호출하고 데이터를 가지고 간 이후 commit을 수행하기 전 consumer에서 장애가 발생하면 어떻게 될까요?
예를들어 50건의 레코드만 읽은 뒤 장애가 발생했다면 앞의 50건의 레코드는 작업이 수행되었지만 commit이 되지 않아 읽지 않은 레코드로 판단하고 다시 중복처리가 될 수 있습니다.
Kafka에서는 상황에 따라 consumer group rebalancing이 발생합니다.
1. 애플리케이션을 배포하는 상황에 consumer 생성/삭제가 될 때
2. 시간 내에 poll 요청 실패(max.poll.interval.ms 설정시간을 넘긴 경우)
3. 컨슈머가 일정시간 내에 heartbeat를 보내지 못하는 경우 (consumer에 문제가 발생)
consumer group rebalancing이란 특정 consumer에 문제가 생겨 더 이상 메시지를 처리할 수 없다고 판단하고 소유권을 다른 컨슈머에게 이관합니다.
어떻게 해결할 수 있을까?
1. max.poll.records 수를 1로 설정하기
2. auto commit이 아닌 수동 commit 활용하기(MANUAL_IMMEDIATE 등을 활용하여 Ack 처리를 컨슈머에서 직접 처리) - 물론 이런 경우에도 수동 commit 전에 문제가 발생하면 해당 메시지에 대해 다시 처리가 될 수 있습니다.
참고자료
https://docs.confluent.io/platform/current/clients/consumer.html
https://dydwnsekd.tistory.com/80
https://dongjuppp.tistory.com/86