모종닷컴

Exactly Once Semantics 본문

Programming/Apache Kafka

Exactly Once Semantics

모종 2023. 11. 5. 23:29
반응형

Kafka Producer를 한 번이라도 봤다면 Acks 및 retry 관련 설정을 본 적이 있을 겁니다. 이와 관련돼서 항상 등장하는 단어 중 하나는 Exactly One Semantics입니다. Exactly One Semantics는 정확히 한 번만 레코드를 저장한다입니다. Acks, Retry 설정을 조정해 보면서 이 Exactly Once Semantics가 왜 필요한 건지 알아보도록 하겠습니다.

 

Acks, Retry 설정을 통해 메시지를 전달하는 방식에는 크게 3가지로 분류됩니다. At Most Once, At Least Once, Exactly Once입니다.

 

At Most Once Delivery Semantics

최대 한 번만 전송 시도를 하는 방식입니다. Retry 설정을 0, Acks = 0으로 하게 되는 경우(=Fire And Forget) 이 방식을 사용할 수 있습니다. acks는 무슨 값으로 넣든 이 방식의 단점을 재현해 볼 수 있기 때문에 테스트할 때는 아무 값이나 넣어도 상관없을 것 같습니다.

이처럼 At Most Once 방식에서는 메시지 유실 가능성이 존재합니다.

유실되어도 상관없는 토픽인 경우 위 방식을 사용할 수 있습니다. 유실되어도 상관없는 토픽이라고 생각하니 Acks도 그냥 0으로 설정하는 게 성능에도 더 유리하겠네요.

At Least Once Delivery Semantics

적어도 한번 이상 전송을 하는 방식입니다. Retry 설정이 0 이상인 경우 이 방식을 사용하게 됩니다. 아래와 같은 상황을 가정해 보겠습니다.

Producer가 카프카에 메시지를 전송하였습니다. 그리고 카프카에서 해당 메시지를 저장하는 데 성공하게 됩니다. 카프카에서 메시지를 성공적으로 저장하게 되어서 Ack를 producer에 전송하려고 합니다. 이때 네트워크 문제나 어떤 알 수 없는 문제에 의해서 Producer가 Ack를 받지 못하게 되었습니다.

이 경우 At Least Once 방식의 단점이 드러나게 됩니다. Producer에는 ack를 받지 못했고 응답 대기 시간이 지나 실패했고, Retry 설정으로 인해 재시도를 하게 됩니다. 카프카에서는 해당 메시지가 이미 자신이 저장한 메시지인지 아닌지 모르고 다시 한번 같은 메시지를 저장하게 됩니다.

이처럼 At Least Once Delivery 방식에는 메시지가 중복 저장될 수 있다는 특징을 가지고 있습니다.

Exactly Once Delivery Semantics

잠깐 봤듯이 At Most, At Least 방식에는 메시지 중복 가능성, 메시지 유실 가능성이 존재하게 됩니다. 이를 보완하기 위해 만들어진 방식으로 Exactly Once 방식이 생겼습니다. 이는 정확히 메시지가 한 번만 저장되도록 하는 방법입니다. 

이전 두 방식에서는 retry, acks 설정으로 재현이 가능했는데 Exactly Once 방식을 사용하기 위해서는 추가적으로 한 가지 설정이 더 들어가게 됩니다. enable.idempotence를 true로 설정해주어야 합니다. Exactly Once에서는 중복 전송되는 동일 메시지를 필터링할 수 있기에 Retry를 0 이상의 값으로 넣어서 메시지 유실 가능성을 없애도록 합시다. 또한 메시지 저장에 실패해서 유실 가능성을 없애기 위해서 acks도 -1 (all)로 설정하도록 합니다.

그럼 이제 Exactly Once에서는 어떤 과정을 통해 문제들을 해결하는지 알아보도록 하겠습니다.

Exactly Once 방식에서는 가장 처음 브로커와 통신하기 전 Producer Id를 발급하게 됩니다. 이 발급받은 producer id는 프로듀서에서 잘 저장하고 있다가 모든 전송하는 메시지에 이 producer id를 같이 전송하도록 되어있습니다. 추가로 메시지에 Sequence라는 일련의 번호를 뜻하는 값도 같이 전송됩니다. 

어떤 메시지를 전송한다고 가정해 보겠습니다. "hello world"라는 메시지를 전송하게 되면 처음에 자신에게 할당된 producer id (1000)과 sequence (100)을 전송하게 됩니다.

브로커에서는 이 메시지를 받게 되면 가장 처음 자신의 메모리에 저장된 producer id에 대한 메타 정보값들을 가져오게 됩니다. 해당 메타 정보에는 pid와 sequence 값이 저장되어 있습니다. 그러면 현재 전달받은 producer id와 sequence 값이 올바르게 들어왔는지 체크를 할 수 있습니다.

만약 메모리에 저장된 producer.id (1000), sequence(200)이라는 메타 정보가 있다면 현재 저장하려는 메시지의 sequence 값이 현재 자신에게 저장한 sequence(200) 보다 작으므로 이는 브로커에 저장하지 않고 프로듀서에게는 적당한 메시지를 알려주게 됩니다.

만약 메모리에 1000, 99이라는 메타정보가 저장되어 있다면 현재 메시지가 자신이 받길 기대하던 메시지이므로 해당 메시지를 저장하기 이한 과정을 처리하게 됩니다. 저장이 잘 되었다면 이 메타정보를 1000, 100 값으로 업데이트하고 프로듀서에게 성공했다는 메시지를 주게 됩니다.

이러한 과정이 추가되면서 카프카에서는 중복 처리 가능성과 메시지 유실 가능성을 해결할 수 있습니다.

반응형

'Programming > Apache Kafka' 카테고리의 다른 글

Quorum based Controller  (0) 2024.01.07
KRaft 합의 알고리즘  (0) 2024.01.07
카프카 모니터링 - 메트릭  (0) 2023.12.02
Kafka Transaction  (0) 2023.11.18