카프카 멱등성 및 이벤트 일관성 보장하기

카프카 멱등성 (Idempotency) 및 이벤트 일관성 (Eventual Consistency) 보장하기

안녕하세요. Kafka 통해 많은 용도로 사용되고 있습니다. kafka 는 설정을 통해 내가 원하는 수준의 신뢰성 확보 할 수 있다는 것이 장점 입니다.

이번에 소개 드리는 설정 통해 신뢰성을 확보하면서 Kafka 를 활용 해보도록 하겠습니다.

Producer 메시지 전달 보장 (Message Delivery Guarantees) 수준 정하기

Producer 에서 Kafka 브로커에게 메시지 발행 할때 메시지 전달 보장 수준이 있습니다. 총 세가지 수준이 있는데요.

  • At most once (최대 한 번)
  • At least once (최소 한 번)
  • Exactly once (정확히 한 번)

비동기식 통신에 메시지 큐를 이용하기로 결정했다면, 메시지 전달 보장 (Message Delivery Guarantees) 수준에 대해 고려해야한다. 주로 다음과 같은 세 가지 수준이 있다.

  • At most once (최대 한 번)
  • At least once (최소 한 번)
  • Exactly once (정확히 한 번)

각각 자세하게 알아보도록 하겠습니다.

At most once (최대 한 번)

메세지가 딱 한번만 전송됩니다. Producer 에서 Kafka broker 에게 메시지 전송 후 만약 broker 으로부터 응답 확인 (Ack) 을 받지 못하더라도 다시 재전송을 하지 않습니다.
중복 방지를 할 수 있겠지만 만약 네트워크 문제로 메시지를 정상적으로 broker 로 전송하지 못 할 경우 데이터 유실이 발생 할 수 있습니다.

At least once (최소 한 번)

메시지 유실을 허용하지 않는 전략으로써 만약 Producer 에서 Kafka broker 에게 메시지 전송 후 broker 으로부터 응답 확인 (Ack) 데이터를 받지 못하면 다시 재전송을 하게 도비니다.

이때 broker 가 정상적으로 메시지를 받았지만 저장을 못해서 발생된 문제인지 아니면 메시지 조차 못 받았는지 Producer 입장으로 확인 할 수 없어 다시 메시지를 전송 하게 됩니다.

이런 점을 보았을때 At least once (최소 한 번) 는 메시지 유실에 대한 방지에 목적을 두었지만 상황에 따라 메시지 중복은 발생 할 수 있습니다.

Exactly once (정확히 한 번)

정확히 한번에 처리 하는 방식이라고 생각하면 됩니다. 즉 단 한번으로 메시지 유실도 없고, 중복 메시지도 발생하지 않으면서 처리하는 방식 인데요.
이러한 두가지 조건을 만족하기 위해서는 ECO 시스템이 필요 합니다. Producer 가 Kafka broker 에게 메시지 발생시 Producer ID + 시퀀스 넘버 (유니크 키) 값 함께 전송 하게 됩니다.
만약 중복 메시지가 전송 된다면 동일한 Producer ID + 시퀀스 넘버 값이 전송하게 될테고 중복으로 확인된다면 처리 하지 않도록 합니다.

반대로 메시지 발행 후 Producer 으로 응답 확인 Ack 값이 전송 하지 않으시 (처음 broker 로 메시지 도착 조차 안했을 경우) 다시 재전송 해서 처리 하게 됩니다.

Producer Acknowledgements (acks) 설정

Kafka 의 acks 설정은 Producer 에서 broker 에게 메시지 발행 후 Producer 에게 ack 값 수준 이라고 보면 됩니다.

  • acks 0
  • acks 1
  • acks -1 (all)

대표적으로 이렇게 총 3가지가 있습니다. 하나씩 알아보도록 하겠습니다.

ack = 0

acks=0 설정은 최대 한번(At most once) 전송 전략에 해당합니다.
Producer 에서 broker 에게 메시지 발행 후 broker 으로 부터 ack 값 응답을 기다리지 않고 처리 하게 됩니다. 즉 메시지 전송만 하면 성공으로 간주 됩니다.

앞써 최대 한번(At most once) 에 대해 이야기 한대로 broker에게 문제가 발생되어서 처리 하지 않을시 작업이 중단 되면 메시지 유실로 이어집니다.

ack = 1

ack = 1 설정은 At least once (최소 한 번) 전송 전략에 해당됩니다.
이 설정은 Producer 에서 broker 내에 있는 리더 파티션 에 데이터 전송 하고 안정적으로 리더 파티션 으로 저장되었면 Ack 응답을 해주면서 처리가 완료하게 됩니다.

만약 ProducerAck 응답을 정상적으로 못 받을 경우 다시 재전송을 하게 됩니다.

하지만 리더 파티션 에서만 해당되는 경우이고 만약 리더 파이션 으로부터 복제된 파티션도 정상적으로 데이터를 복제 했는지는 체크 하지 않습니다. 만약 레플리카 들이 데이터 복제가 되지 않을 경우 데이터 유실이 발생 될 수 있습니다.

ack -1 (all)

Producer 에서 broker 내에 있는 리더 파티션 뿐만 아니라 레플라카 브로커에게도 정상적으로 복제 되는지 체크 후 producer 에게 ack 응답 하게 됩니다.

Exactly Once Semantics (EOS) 이용해서 멱등성 보장 하기

Producer 중복 발생 케이스
ack 옵션 중 ack = 1, ack -1 (all) 으로 설정 후 producerbroker 에게 메시지를 발행 후 ack 응답을 보내지 않았는데 마침 성공적으로 broker 에 메시지를 저장 하게 된다면
producer 는 이를 알지 못하니 다시 재전송을 하게 되어서 중복 처리 하게 됩니다.

Produser EOS

이러한 문제를 해결하기 위해 애초에 producer 가 메시지 발행시 Producer ID + 시퀀스 넘버 (유니크 키) 값 함께 전송 하게 됩니다.

만약 해당 유니크 값을 이용해서 중복 메시지 발행 하더라도 broker 에서는 유니크 값을 인지해 중복 처리 방지 해서 멱등성을 유지 하도록 합니다.

해당 옵션값은 enable.idempotence 에서 true 로 설정 하면 됩니다.

Consumer 메시지 일관성 유지하기

Consume 하는 과정에서 메시지를 중복 메시지 발행 및 누락 되는 케이스가 있습니다. 이 부분에 있어서 자세히 알아보도록 하겠습니다.

자동 커밋으로 인해 누락 발생

자동 커밋 누락 1
이미지에서 보시면 해당 파티션에 데이터가 저장 되어 있습니다. 1번 Offset 부터 차례대로 consume 를 하고 있는데요.

자동 커밋 누락 2
104번~105번 까지 fetch 통해 데이터를 처리 한다고 했을때 104번을 데이터 처리를 하고 곧 바로 auto.commit.interval.ms 설정한 자동 커밋 주기에 커밋을 한다고 가정 하겠습니다.
그럼 104 번 하고 105 번 은 커밋을 진행 합니다.

갑작스럽게 이후 Rebalnce 발생한다고 가정 하겠습니다. Rebalnce 발생하고 나서 다시 brokercommit 한 기준(105 번까지 commit) 으로

자동 커밋 누락 3

106번 데이터 부터 consume 하게 됩니다. 그럼 105 번은 누락되는 일이 발생 됩니다.

자동 커밋 및 수동 커밋으로 인해 중복 발생

이번에는 자동 커밋으로 인해 중복 이벤트 발생 되는 케이스를 확인 해보겠습니다.

자동 커밋 중복 1

104번~105번 까지 fetch 통해 데이터 consume 하고 있는 과정에서 104 번까지 데이터 처리 했다고 가정 하겠습니다. 그런데 이때 갑자기 Rebalnce 발생 됩니다.

자동 커밋 중복 2

Rebalnce 처리가 끝나게 되면 파티션과 consumer 와 관계가 재형성 하게 됩니다. broker 입장에서는 103번까지만 데이터 처리를 했다고 보고 104번 부터 consume 하게 되는데요. 그럼 104번 은 중복 메시지가 발생 됩니다.

이와 같이 문제가 발생되는 주요 원인은 Rebalnce 발생하고 나서 문제가 발생된다는 점 입니다. 자주 Rebalnce 발생 된다면 중복 consume 및 누락 consume 가 발생 될 수 있습니다.
Rebalnce 경우는 파티션이 추가 되거나 consumer group 내 consumer 가 추가 및 제거 되는 경우도 발생 됩니다.

예를들어서
session.timeout.ms (consumer 로 부터 설정한 시간 값까지 신호가 없을때 timeout 발생)
heatbeat.interval.ms (consumer 가 broker 에게 정상적인 상태인지 설정한 시간 값 주기로 신호 발생) 설정한 값으로 인해 Rebalnce 발생 될 수 있습니다.

session.timeout.ms 설정 시간 대비 heatbeat.interval.ms 값이 초과 되거나 근접하면 Rebalnce 발생 될 수 있는 가능성이 큽니다.
보통 session.timeout.ms 값 대비 heatbeat.interval.ms 값을 1/3 로 설정 합니다.

또 하나는 max.poll.interval.ms 값 입니다. 이 시간을 너무 짧게 주면 문제가 발생 될수 있는데요. 예를들어서 consume 해서 너무 긴 로직을 수행 한다고 했을때
설정한 max.poll.interval.ms 시간 동안 poll 을 안 할 경우 Rebalnce 발생 될 수 있습니다.

그리고 가능한 자동 커밋 보다 수동 커밋을 지향 해야 합니다. 앞써 자동 커밋으로 인해 메시지 누락되는 현상이 발생 됩니다. 차라리 누락 되는 문제 보다 중복으로 메시지가 발생 되는 것이 안전 합니다.
중복 메시지 발생시 멱등성 키 값을 활용해서 중복 처리 안되도록 내부적으로 로직 구성을 해야 합니다.


Copyright 201- syh8088. 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.

💰

×

Help us with donation