어떤 상황에서 같은 이벤트가 동시에 들어올까?
1. Upstream 시스템이 중복 전송할 때
- 예: 서버 장애로 재전송 → Kafka에 동일 메시지 두 번 push됨
- 예: 버튼 두 번 클릭 → API 두 번 호출 → Kafka 두 번 전송
2. 이벤트 발생 기준이 애매할 때
- 예: 상태가 저장되기 전에 이벤트 발생 → 동일 내용 여러 번 발생
- 예: 알림 대상 유저가 여러 명인데, 같은 알림ID로 반복 전송됨
3. 컨슈머가 빠르게 재시도할 때
- 메시지 처리 실패 → offset을 커밋 안함 → Kafka는 같은 메시지를 재전송
대처법
1. Idempotent 처리
"같은 메시지가 여러 번 들어와도 결과는 한 번만 발생하도록"
if (!alreadyProcessed(event.getId())) { saveToDb(event); markAsProcessed(event.getId()); }
- eventId 기준으로 Redis나 DB에서 처리 여부 캐싱
- Redis SETNX(set if not exists)로 처리 중복 방지 가능
2. Kafka 메시지 키를 설정 - > 순서보장
ProducerRecord("topic", key = event.id, value = event)
- 같은 key는 같은 파티션에 들어가고, 순서 보장
- 컨슈머에서 "같은 이벤트"가 순서 보장되는 상황이면 중복 처리도 더 쉽다
- Key 없이 아무 데나 보내면 → 3개의 알림이 서로 다른 파티션 → 동시에 처리됨 → 중복 처리될 가능성 높음
- Key를 주면 → 모두 같은 파티션 → Kafka가 순서대로 보냄 → 하나씩 처리되므로 우리가 중복 체크하기 쉬움
3. 중복 방지용 락 사용 (Redis 등)
val locked = redisson.tryLock("event:${event.id}", 3, 10, TimeUnit.SECONDS)
if (locked)
{
try { process(event) }
finally
{ lock.unlock()}
}
- 여러 컨슈머 인스턴스가 있을 때 하나만 처리하게 만듦
- 실시간 동시성 문제에서 꽤 효과적
4. DB unique 제약 조건 활용
- 이벤트 결과를 저장할 때 중복 저장 방지용으로 PK 또는 UNIQUE 제약 설정
CREATE UNIQUE INDEX ux_event_id ON processed_events(event_id);
- 중복이 들어와도 DB가 차단
💡 예시
알림 센터에서 같은 alarmId=123이 3번 연속 들어온 경우
- Kafka 컨슈머에서는 Redis에 SETNX("alarm:123") 시도
- 성공 시 → DB 저장 + 사용자에게 푸시 전송
- 실패 시 → 이미 처리 중이거나 완료된 알림이므로 무시
'TIL' 카테고리의 다른 글
| 소켓에서 레디스를 왜 쓸까? (0) | 2025.06.29 |
|---|---|
| istio란? (0) | 2025.05.29 |
| Spring 트랜잭션 RollbackFor (0) | 2025.05.22 |
| Spring 트랜잭션 전파 레벨 (0) | 2025.05.22 |
| Flutter 앱 아이콘 / 스플래시 이미지 적용법 (0) | 2025.05.21 |