Loading the catalog…
Loading the catalog…
Intro Kafka는 주로 대용량 실시간 데이터를 안정적이고 빠르게 처리하기 위해 사용한다. 주요 특징은 디스크 기반 데이터 영속성을 가져 시스템 장애 시에도 데이터 유실 없이 복구할 수 있다. 그러면 어떻게 사용해야 "이벤트 유실을 최소화할 수 있을지", "이벤트 유실을 관리할 수 있을지" 정리해보려 한다. 이벤트 유실없이 관리하기 이벤트 유실 지점에 관련해서 Spring Framework & Kafka 관점에서 알아보자. 여기에서 브로커는 적어도 레플리카(replica)가 3개 이상 있는 상황을 가정한다. 메시지 전송 방식(Message Delivery Semantics) 각 부분별로 나누어 보기 전에 메시지 전송 방식에 대해 알아보자. At most once : 메시지가 최대 한 번만 전달되며, 유실될 수 있지만 중복은 절대 발생하지 않습니다. At least once : 메시지가 절대 유실되지 않음을 보장하지만, 네트워크 재시도 등으로 인해 중복 전달(처리)될 수 있습니다. Exactly once : : 중복이나 유실 없이 메시지를 정확히 한 번만 처리한 것과 같은 결과를 보장합니다. At most moce의 경우에는 특정 상황에서 중간 이벤트들이 유실될 수 있으며, Exactly once의 경우 추가적인 오버헤드가 발생하여 처리 지연이 발생할 수 있다. 그래서 일반적으로는 At least once 방식을 차용하고 각 이벤트에 ID값을 만들어 컨슈머에서 멱등성 처리를 해주는 것이 일반적이다. 프로듀서 (Spring Producer) acks = all (-1) 리더 파티션뿐만 아니라 동기화된 모든 팔로워(ISR)에 복제가 완료될 때까지 프로듀서가 응답을 기다립니다. '0'인 경우에는 응답을 기다리지 않고, '1'인 경우에는 Broker Leader 의 응답 확인만을 기다립니다. 처리 속도와 영속성의 트레이드오프를 고려하여 설정이 필요합니다. enable.idempotence = true (멱등성 프로듀서) 네트워크 재시도 시 브로커에 중복 적재되는 것을 방지합니다. 프로듀서 ID(PID)와 시퀀스 번호를 헤더에 붙여 중복 저장을 걸러냅니다. Spring Boot 최신 버전에서는 기본적으로 권장/활성화됨 retries = Integer.MAX_VALUE 및 delivery.timeout.ms 설정 일시적인 장애 시 재시도 횟수를 충분히 확보하고, 전체 전송 타임아웃 안에서 안전하게 재시도하도록 보장합니다. Spring KafkaTemplate 비동기 콜백 처리 CompletableFuture 형태로 반환되는 전송 결과를 반드시 로깅하거나 실패 시 재처리(예: 로컬 DB 저장 후 재전송 아웃박스 패턴)를 태워야 합니다. public class EventProducer { private final KafkaTemplate<String, String> kafkaTemplate; private final FailedKafkaEventRepository failedEventRepository; public void sendEvent(String topic, String key, String payload) { CompletableFuture<SendResult<String, String>> future = kafkaTemplate.send(topic, key, payload); future.whenComplete((result, ex) -> { if (ex == null) { // 전송 성공: 파티션 및 오프셋 정보 로깅 log.info("Kafka send success -> topic: {}, partition: {}, offset: {}, key: {}", result.getRecordMetadata().topic(), result.getRecordMetadata().partition(), result.getRecordMetadata().offset(), key); } else { // 전송 실패: 에러 로깅 및 로컬 DB 저장 log.error("Kafka send failed -> topic: {}, key: {}, payload: {}, cause: {}", topic, key, payload, ex.getMessage(), ex); saveFailedEvent(topic, key, payload, ex.getMessage()); } }); } 브로커 (Kafka Cluster) 브러커 자체가 복제 설정이 부실하다면, 리더 장애 시 데이터가 증발할 수 있다. 그래서 아래와 같은 설정을 진행하는 것이 좋다. replication.factor >= 3 토픽 생성 시 파티션의 복제본 수를 최소 3개 이상으로 유지합니다. min.insync.replicas = 2 acks=all 일 때 최소 몇 개의 복제본(리더 포함)에 데이터가 써져야 성공으로 간주할지 지정합니다. replication.factor=3 에 min.insync.replicas=2 조합을 쓰면 브로커 1대가 죽어도 안전하게 쓰기 작업이 지속됩니다. unclean.leader.election.enable = false ISR(In-Sync Replicas)에 속하지 않은 뒤처진 팔로워가 리더로 승격되는 것을 막습니다. 승격될 경우 동기화되지 않은 과거 데이터가 유실(Trunkation)될 수 있습니다. 컨슈머 (Spring @KafkaListener ) 컨슈머 측 유실의 90% 이상은 "비즈니스 로직(DB 저장, 외부 API 호출 등)이 끝나기 전에 오프셋이 먼저 커밋되는 경우" 발생합니다. enable-auto-commit = false (자동 커밋 비활성화) 기본 설정인 자동 커밋은 폴링해 온 즉시 일정 주기로 오프셋을 커밋하므로, 처리 도중 앱이 다운되면 메시지가 유실됩니다. Spring AckMode.MANUAL_IMMEDIATE 또는 RECORD 적용 비즈니스 로직 처리가 완전히 끝난 시점에 수동으로 Acknowledgment.acknowledge()를 호출하도록 설정합니다. // 컨슈머 구현 @KafkaListener(topics = "order-events", groupId = "order-group") public void listen(ConsumerRecord<String, String> record, Acknowledgment ack) { try { processBusinessLogic(record.value()); // 비즈니스 로직 처리 ack.acknowledge(); // 성공 시에만 오프셋 수동 커밋 } catch (Exception e) { // 에러 핸들러나 재시도 토픽(DLT)으로 위임 throw e; } } 장애 및 에러 대응 메시지 포맷 오류나 외부 의존성 장애로 특정 메시지가 계속 실패하면 무한 루프에 빠지거나 누락될 수 있습니다. DefaultErrorHandler + DeadLetterPublishingRecoverer (DLT) 지정된 횟수(예: 3회 백오프)만큼 재시도 후에도 실패한 메시지는 Dead Letter Topic(DLT)으로 발행하여 나중에 수동 분석 및 재처리할 수 있도록 격리합니다. 참고 자료 올리브영 테크블로그 - Kafka 메시지 중복 및 유실 케이스별 해결 방법 Kafka 장애 상황에서 메시지 유실 없이 처리하기 위한 설계 전략
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
Kafka - 메시지 유실되지 않게 하는 방법?. Intro Kafka는 주로 대용량 실시간 데이터를 안정적이고 빠르게 처리하기 위해 사용한다. 주요 특징은 디스크 기반 데이터 영속성을 가져 시스템 장애 시에도 데이터 유실 없이 복구할 수 있다. 그러면 어떻게 사용해야 "이벤트 유실을 최소화할 수 있을지", "이벤트 유실을 관리할 수 있을지" 정리해보려 한다. 이벤트 유실없이 관리하기 이벤트 유실 지점에 관련해서 Spring Framework & Kafka 관점에서 알아보자. 여기에서 브로커는 적어도 레플리카(replica)가 3개 이상 있는 상황을 가정한다. 메시지 전송 방식(Message Delivery Semantics) 각 부분별로 나누어 보기 전에 메시지 전송 방식에 대해 알아보자. At most…
Open source