[시스템 사고] kafka vs RabbitMQ (IN 알림 시스템)

배현서·2024년 11월 28일

시스템 사고

목록 보기
4/10
post-thumbnail

알림 시스템 아키텍처 선택에 대한 고찰

알림 시스템을 설계할 때 중요한 것은 메시지의 신뢰성과 처리의 원자성이다. 초기에는 Java의 CompletableFuture를 활용한 비동기 처리로 시스템을 구현했으나, 알림 발송과 로그 저장 과정에서 여러 문제점이 발생했다. 특히 파티셔닝된 로그 테이블에 대한 트랜잭션 처리와 실패 시의 재시도 로직 구현에서 어려움을 겪었다.

이러한 문제를 해결하기 위해 메시지 큐 도입을 검토하던 중, 일부 기업들이 Kafka를 사용하여 알림 시스템을 구현했다는 사례를 발견했다. 이는 메시지 큐(RabbitMQ)와 분산 이벤트 스트리밍 플랫폼(Kafka)의 차이점을 더 깊이 이해하고, 우리 시스템에 더 적합한 솔루션을 선택해야 할 필요성을 제기했다.

두 시스템의 특성을 비교 분석하고, 현재 구현하고자 하는 알림 시스템의 요구사항을 고려한 결과, RabbitMQ가 더 적합한 선택이라 판단했다. 이러한 판단의 근거와 상세한 분석 내용을 아래와 같이 정리했다.

알림 시스템 구현 과정과 문제 해결

  1. 초기 접근: CompletableFuture를 이용한 비동기 처리
java
@Service
@Slf4j
public class NotificationService {

    @Async
    public CompletableFuture<Void> sendNotification(NotificationHistory notification) {
        return CompletableFuture.runAsync(() -> {
            try {
                sendPushNotification(notification);
                // 알림 로그 파티셔닝 저장
                saveNotificationLog(notification);
            } catch (Exception e) {
                // 실패 처리 및 로그 저장이 각각 별도 트랜잭션으로 발생
                // 알림 실패와 로그 저장의 원자성 보장이 어려움
                log.error("Failed to send notification: {}", e.getMessage());
            }
        }, Executors.newVirtualThreadPerTaskExecutor());
    }
    private void saveNotificationLog(NotificationHistory notification) {
        // 파티셔닝된 테이블에 로그 저장
        // 알림 실패시 로그 상태 관리가 복잡
    }
}
  1. 발생한 문제점:
    • 알림 실패시 로그 상태 업데이트가 누락될 수 있음
    • 파티셔닝된 로그 테이블에 대한 트랜잭션 처리 복잡
    • 재시도 처리와 로그 상태 동기화의 어려움
    • 대량 알림 발송시 로그 처리 병목 현상

이런 문제점으로 메세지 큐를 도입해 아래와 같은 이점을 얻을 수 있다고 생각했다.

  1. 알림 발송과 로그 저장의 원자성 보장
  2. 실패한 알림의 재처리와 로그 상태 관리 용이
  3. 파티셔닝된 로그 테이블에 대한 안정적인 쓰기 작업
  4. 시스템 장애시에도 메시지 보존으로 데이터 정합성 유지

하지만!!
알림 시스템을 설계 할때 특정 상황에서는 kafka를 통해 구현한다는 레퍼런스를 보고 메세지큐를 이용한 설계와 분산 이벤트 스트리밍을 이용한 설계가 어떤 점에서 다른지 궁금해졌다.


알림 시스템의 주요 특성:

  1. 실시간성 요구: 알림은 최대한 빠르게 전달되어야 함
  2. 메시지 신뢰성: 알림이 누락되면 안 됨
  3. 메시지 순서: 특정 사용자의 알림은 순서가 보장되어야 함
  4. 우선순위 처리: 긴급 알림은 우선적으로 처리 필요
  5. 일회성 소비: 한 번 전송된 알림은 재처리할 필요 없음
  6. 복잡한 라우팅: 알림 유형(푸시,SMS,이메일)별로 다른 처리 필요

RabbitMQ를 이용한 설계:

  1. 메시지 보증과 순서
    • 메시지 전달 보장(acknowledgment) 메커니즘 내장
    • 순서 보장이 기본적으로 제공됨
    • 알림의 신뢰성과 순서 보장 요구사항에 적합
  2. 우선순위 지원
    • 우선순위 큐 기능 제공
    • 긴급 알림을 우선적으로 처리 가능
  3. 복잡한 라우팅
    • Exchange와 Queue 바인딩을 통한 유연한 라우팅
    • 알림 유형별로 다른 처리가 가능
  4. 푸시 기반 모델
    • 브로커가 능동적으로 메시지 전달
    • 실시간성이 중요한 알림에 적합

이런 설계에서 Kafka가 적합하지 않은 이유:

  1. 과도한 스펙
    • 초당 수백만 건의 처리량은 일반적인 알림 시스템에서 불필요
    • 복잡한 아키텍처로 인한 운영 부담
  2. 부족한 기능
    • 우선순위 큐 미지원
    • 복잡한 라우팅 구현이 어려움
  3. 풀 기반 모델
    • 소비자가 직접 메시지를 가져가는 방식
    • 실시간 알림에는 부적합할 수 있음
  4. 영구 저장 특성
    • 메시지를 보존 기간동안 저장
    • 일회성 알림에는 불필요한 리소스 사용

참고 : kafka vs rabbitmq

결론: 알림 전송과 로그 저장 시스템에 RabbitMQ가 적합한 이유

1. 트랜잭션 특성
- 알림 전송과 로그 저장이 하나의 트랜잭션으로 처리되어야 함
- RabbitMQ의 메시지 확인(ACK) 메커니즘으로 원자성 보장
- 실패 시 자동으로 Dead Letter Queue로 이동하여 재처리 가능
2. 로그 저장 목적
- 알림 전송 결과를 단순히 기록하는 것이 목적
- 로그의 장기 보관이나 재처리가 필요없음
- Kafka의 영구 저장 특성은 이 경우 오버스펙
3. 즉시성
- 알림 전송 즉시 로그가 저장되어야 함
- RabbitMQ의 푸시 기반 모델이 이 요구사항에 적합
- Kafka의 풀 모델은 불필요한 지연 발생 가능
4. 구현 복잡도
- 단순한 알림 전송과 로그 저장에는 RabbitMQ의 단순한 구조가 적합
- Kafka의 복잡한 아키텍처는 현재 요구사항에 과도

0개의 댓글