Kafka

Kafka는 여러 서버에 데이터를 분산 저장하여 높은 확장성과 내결함성을 제공하는 분산 스트리밍 플랫폼으로 알려져 있어요. 리소스나 애플리케이션에 따라 달라지겠지만 초당 수백만 건의 메시지를 실시간으로 주고 받아서 처리 할 수 있어요. Go언어로 지원하는 패키지는 sarama와 confluent-kafka-go 등이 있는데 이번에는 우리가 사용중인 sarama의 Producer를 안전하게 사용하는 방법을 이야기 해 보려 해요.

SyncProducer vs AsyncProducer(동기 vs 비동기 생산자)

Producer는 Kafka로 메시지를 보내는 역할을 가지고 있어요. Sync(동기)와 Async(비동기) 2가지 유형이 있는데 각각 장단점이 분명하기 때문에 잘 선택해야 해요. SyncProducer는 HTTP 요청과 같이 Kafka로 메시지를 보내고 확인(ACK) 응답이 올 때까지 기다려요. 그래서, 메시지가 제대로 카프카로 전송 되었는지 알 수 있어요. AsyncProducer는 Kafka에 메시지를 전송하는 것이 비동기적으로 처리돼요. 메시지를 내부 버퍼(channel)에 집어 넣으면 끝이에요. 이렇게, 메시지를 내부 버퍼에 모아두고 일정시간이 지나거나 버퍼가 일정 크기에 도달하면 배치로 보내기 때문에 SyncProducer보다 상대적으로 더 많은 메시지를 빠르게 처리할 수 있어요.

What to choose?(뭘 선택하지?)

애플리케이션이나 기능의 특성에 따라 어떤 producer를 사용할 것인지 잘 선택해야 해요. 선택 기준은 보통 신뢰성이나 성능 요구사항에 따라 결정 돼요. 다음과 같이 상황에 따라 적합한 유형의 생산자를 선택하는 것이 좋아요.

높은 처리량과 손실을 감수할 수 있을 때 AsyncProducer를 사용한다고 했지만, 최대한 데이터의 손실을 예방하기 위해 Sarama에서 제공되는 Config에 대해 살펴 봐요.

Timeout(타임아웃)

타임아웃은 불안정한 환경에서 데이터를 주고 받을 때 꼭 필요해요. 예를 들어, HTTP, TCP 등의 프로토콜을 사용하는 네트워크 통신은 상황에 따라 지연/응답 시간이 길어질 수 있기 때문에 타임아웃을 통해 무한정 기다리지 않고 실패를 빠르게 감지하여 재시도나 차단 등의 조치를 취할 수 있어요. Sarama는 Kafka 브로커에 연결하는 모든 클라이언트에 다음 세가지 설정을 제공하고 있어요. 3개 설정은 모두 디폴트로 최대 30초까지 기다리도록 설정되어 있어요.

Producer의 타임아웃 설정은 다음과 같아요. 생산자가 브로커로 한개 메시지를 보내기 위해 한 번의 요청과 응답을 기다리는 최대 시간이고 기본값은 10초로 설정돼요. 재시도 할 때도 동일하게 적용되며, 3번 재시도 하도록 설정했다면 각 시도마다 10초(기본값) 안에 요청과 응답이 완료되어야 해요.

JVM 기반의 request.timeout.ms와 동일하며 브로커의 설정인 replica.lag.time.max.ms보다 높게 설정되어야 해요. 더 낮게 설정되면 타임아웃으로 인한 메시지의 중복이나 불필요한 재시도의 가능성이 더 높아져요(replica.lag.time.max.ms 기본값은 30000).

JVM에서 제공하는 delivery.timeout.ms을 Sarama는 제공하지 않고 있어요. delivery.timeout.ms는 재시도와 지연(linger.ms)을 포함한 한 개 메시지 발행에 주어진 총 시간이에요(delivery.timeout.msrequest.timeout.ms + linger.ms).