Загружаем каталог…
Загружаем каталог…
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 장애 상황에서 메시지 유실 없이 처리하기 위한 설계 전략
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
Kafka - 메시지 유실되지 않게 하는 방법?. Intro Kafka는 주로 대용량 실시간 데이터를 안정적이고 빠르게 처리하기 위해 사용한다. 주요 특징은 디스크 기반 데이터 영속성을 가져 시스템 장애 시에도 데이터 유실 없이 복구할 수 있다. 그러면 어떻게 사용해야 "이벤트 유실을 최소화할 수 있을지", "이벤트 유실을 관리할 수 있을지" 정리해보려 한다. 이벤트 유실없이 관리하기 이벤트 유실 지점에 관련해서 Spring Framework & Kafka 관점에서 알아보자. 여기에서 브로커는 적어도 레플리카(replica)가 3개 이상 있는 상황을 가정한다. 메시지 전송 방식(Message Delivery Semantics) 각 부분별로 나누어 보기 전에 메시지 전송 방식에 대해 알아보자. At most…
Открыть источник