주문 알림, 결제 확정, 문서 변환처럼 시간이 걸리는 일을 큐로 넘기면 웹 요청은 빨리 끝낼 수 있습니다. 하지만 작업자가 같은 메시지를 여러 번 처리해도 실패하면 어디로 보내야 할까요? 흔히 DLQ, 즉 데드 레터 큐에 옮깁니다. 여기서 중요한 것은 DLQ가 문제 해결 장치가 아니라 실패를 보존하는 장소라는 점입니다. 원인을 고치지 않은 채 전부 다시 넣으면 장애가 반복됩니다.
먼저 ‘왜 실패했는지’를 구분한다
실패는 크게 일시적 장애와 지속적 장애로 나눌 수 있습니다. 외부 API의 잠깐 끊김은 나중에 성공할 수 있습니다. 반면 필수 필드가 없는 메시지나 더는 존재하지 않는 계정에 대한 작업은 같은 조건에서 계속 실패할 가능성이 큽니다. 이 둘을 똑같은 횟수와 간격으로 재시도하면 큐 지연만 커집니다. 에러 코드, 처리 단계, 메시지 스키마 버전, 최초 실패 시각과 시도 횟수를 기록하면 분류가 쉬워집니다.
메시지 본문에는 민감한 정보가 들어갈 수 있습니다. 운영 로그에는 전체 본문을 무분별하게 출력하지 말고 식별자와 원인 요약을 남깁니다. 실제 본문 열람은 권한과 감사 기록을 둡니다. 재처리 과정 자체가 개인정보 노출 경로가 되지 않도록 해야 합니다.
DLQ에 넣는 조건도 운영 정책이다
몇 번 실패하면 격리할지, 어느 오류는 즉시 격리할지, 얼마나 보관할지를 정합니다. 무한 재시도는 다른 정상 작업을 밀어낼 수 있고, 지나치게 빨리 격리하면 잠깐의 네트워크 오류에도 사람이 개입해야 합니다. 큐의 가시성 제한시간과 작업 처리 시간을 맞추지 않으면 처리 중인 메시지가 다시 나타날 수 있습니다. 따라서 ‘한 번만 처리된다’고 가정한 업무 로직은 위험합니다.
멱등성은 같은 사건이 다시 와도 효과가 중복되지 않게 하는 설계입니다. 예를 들어 주문 확정 이벤트에 고유 사건 ID를 붙이고, 이미 처리된 ID라면 메일 재발송이나 재고 차감을 건너뜁니다. 단순히 중복 ID만 저장하는 것이 아니라 DB 변경과 처리 완료 기록을 가능한 한 일관된 트랜잭션 경계 안에서 다뤄야 합니다. 그래야 작업이 중간에 죽어도 다시 시도할 수 있습니다.

재처리는 ‘버튼’이 아니라 절차다
가장 먼저 원인을 고칩니다. 예컨대 외부 서비스가 복구됐는지, 잘못된 스키마를 읽는 소비자가 수정됐는지 확인합니다. 다음에는 메시지를 시간대·오류 유형·고객 영향으로 묶습니다. 오래된 메시지는 현재 상태와 충돌할 수 있으므로 무조건 재실행할 수 없습니다. 취소된 주문에 과거의 승인 이벤트를 다시 적용하면 안 되는 식입니다. 재처리 전 현재 엔티티 상태와 유효기간을 검사할지 결정합니다.
그다음 소량만 재처리하고 성공률, 처리 지연, 외부 API 오류, 중복 효과를 봅니다. 안전하면 속도를 점차 올립니다. AWS의 SQS DLQ 재처리 안내도 이동 속도를 제어할 수 있으며 낮은 속도에서 시작해 원본 큐가 감당하는지 확인하도록 설명합니다. 다만 SQS 기본 재처리는 메시지 내용을 필터링하거나 수정하지 못하므로, 변환이 필요하다면 별도의 안전한 처리 경로가 필요합니다.

어떤 지표를 볼까
DLQ에 새로 들어온 건수만으로는 부족합니다. 지금 남아 있는 메시지 수, 가장 오래된 메시지의 경과 시간, 재처리 후 다시 실패한 비율, 원본 큐의 지연도 함께 봅니다. AWS의 SQS 지표 문서는 DLQ의 자동 이동 메시지가 일반적인 전송 건수 지표에 잡히지 않을 수 있어 가시 메시지 수를 모니터링하도록 안내합니다. 지표 이름은 사용 서비스에 맞게 바꾸되 ‘대기 중인 실패가 쌓이는가’를 보는 목적은 같습니다.
운영 체크리스트
- 재시도 가능한 오류와 영구 오류를 구분했는가?
- 메시지 ID로 중복 실행을 막는가?
- 오래된 메시지가 현재 업무 상태에 유효한지 확인하는가?
- 재처리 전에 원인 수정과 소량 검증을 했는가?
- 재실패·큐 지연·고객 영향이 보이는가?
좋은 DLQ 운영은 ‘실패한 것을 모두 다시 보내기’가 아닙니다. 어떤 일이 실패했는지 설명하고, 다시 처리해도 안전한 것만 통제된 속도로 되돌리는 능력입니다.
#DLQ #데드레터큐 #메시지재처리 #이벤트아키텍처 #멱등성 #재시도설계 #장애대응 #시스템운영 #비동기처리 #백엔드설계