Queue Async Event-driven Design

3줄 요약

  • Queue는 느린 후속 작업을 요청 경로 밖으로 밀어내지만, 그 대가로 지연, 중복, 순서, 재처리 책임을 만든다.
  • Async 설계는 “나중에 처리한다”가 아니라 사용자가 언제 성공으로 느끼고, 시스템은 실패한 일을 어떻게 다시 찾을지 정하는 일이다.
  • Event-driven 구조는 서비스 결합을 낮출 수 있지만, 이벤트 계약, 버전, 관측, DLQ 운영이 없으면 장애를 더 늦게 발견한다.

핵심 정리

  • 동기 처리로 남길 일은 사용자 응답 전에 반드시 확정되어야 하는 일이다. 결제 승인, 주문 생성, 재고 차감처럼 사용자에게 즉시 약속하는 상태가 여기에 가깝다.
  • 비동기로 보낼 일은 늦어져도 사용자 경험을 설명할 수 있고, 실패해도 재처리할 수 있는 일이다. 이메일, 알림, 통계 적재, 정산 보조 데이터 생성이 대표적이다.
  • Queue는 성능과 장애 격리를 개선할 수 있지만 정합성 모델을 즉시 일관성에서 최종 일관성으로 바꾼다.
  • Producer의 발행 성공은 Consumer의 처리 성공이 아니다. message id, correlation id, 상태 저장소, DLQ가 있어야 한 요청의 끝을 추적할 수 있다.
  • Event-driven은 호출자를 모르게 만드는 대신 이벤트 스키마와 의미를 공개 계약으로 만든다. 이벤트 이름, 발생 시점, 재발행 가능성, version 정책이 필요하다.
  • Retry는 일시 장애에는 도움이 되지만 영구 오류에는 장애 증폭이 된다. 재시도 간격, 최대 횟수, DLQ 이동 조건, 수동 재처리 owner를 정해야 한다.
  • 순서 보장은 공짜가 아니다. 같은 주문의 이벤트 순서를 지키려면 partition key나 aggregate 단위 직렬화가 필요하고, 처리량과 병렬성을 일부 포기한다.
  • Spring 메시지 처리는 @KafkaListener나 listener 메서드 하나가 아니라 트랜잭션, ack, idempotency 저장소, 외부 API timeout을 함께 설계하는 일이다.

헷갈리는 지점

  • Queue를 넣으면 요청이 빨라지니 항상 좋다고 생각하기 쉽다. 실제로는 사용자가 기다리는 시간을 줄이는 대신 백그라운드 적체와 재처리 운영을 만든다.
    • 핵심은 성능 개선이 정합성 지연과 운영 복잡도 증가로 바뀐다는 점이다.
  • Event-driven을 느슨한 결합으로만 이해하기 쉽다. 직접 호출 의존은 줄지만 이벤트 계약과 데이터 의미 의존은 남는다.
    • 핵심은 producer와 consumer가 같은 이벤트 의미를 공유해야 하므로 계약 관리가 더 중요해진다는 점이다.
  • Retry를 신뢰성 보장으로 오해하기 쉽다. 중복 실행 방어 없이 retry를 켜면 결제, 포인트, 쿠폰 작업이 여러 번 수행될 수 있다.
    • 핵심은 메시지는 유실보다 중복을 먼저 가정하고 consumer를 idempotent하게 만드는 것이다.
  • DLQ를 만들면 운영 문제가 끝났다고 생각하기 쉽다. DLQ는 실패 메시지를 보관할 뿐이고, 재처리 기준과 owner가 없으면 또 다른 backlog가 된다.
    • 핵심은 DLQ count가 알림, 분류, 수정, 재처리 절차와 연결되어야 한다는 점이다.

확인 질문

  • 확인 질문: 동기 처리와 비동기 처리의 경계는 무엇으로 정해야 하는가?
    • 답변: 사용자가 응답 시점에 확정되었다고 믿는 상태, 실패 시 보상 가능성, 재처리 가능성, 관측 가능성을 기준으로 정한다.
  • 확인 질문: Queue 도입이 바꾸는 설계 축은 무엇인가?
    • 답변: 응답 성능과 장애 격리를 개선할 수 있지만, 정합성은 최종 일관성으로 약해지고 retry, DLQ, lag 관측 같은 운영 복잡도가 늘어난다.
  • 확인 질문: Producer가 메시지를 발행했다는 사실만으로 부족한 이유는 무엇인가?
    • 답변: 발행 성공은 consumer 처리 성공이 아니므로 메시지 상태, idempotency, 실패 보관, 재처리 절차가 없으면 업무 완료를 증명할 수 없다.
  • 확인 질문: Event-driven 설계에서 이벤트 이름보다 더 중요한 것은 무엇인가?
    • 답변: 이벤트가 언제 발생했고 어떤 상태를 보장하며 어떤 consumer가 어떤 버전까지 이해하는지에 대한 계약이다.