메시지 큐와 재시도는 오래 걸리는 작업을 어떻게 나눌까? 확인 응답과 중복 처리

반응형

이메일 발송이나 영상 변환처럼 오래 걸리는 작업을 HTTP 요청 안에서 끝까지 실행하면 사용자는 오래 기다리고, 연결이 끊겼을 때 결과도 모호해진다. 메시지 큐는 요청을 받는 일과 실제 작업을 실행하는 일을 분리한다.

생산자는 해야 할 일을 메시지로 저장하고, 소비자는 메시지를 가져가 실행한 뒤 완료됐다고 알린다. 이 구조는 기다림을 분리하지만 작업이 정확히 한 번만 실행된다는 보장은 자동으로 만들지 않는다.

큐에 넣었다는 것과 작업이 끝났다는 것은 다르다

사용자 요청
  → 작업 메시지를 큐에 저장
  → 접수 응답

소비자
  → 메시지를 가져옴
  → 실제 작업 실행
  → 확인 응답

메시지가 큐에 안전하게 저장되면 서버는 요청을 접수했다고 답할 수 있다. 그러나 소비자가 이메일을 보냈거나 파일을 만들었다는 뜻은 아니다. 화면과 API는 queued, processing, completed, failed처럼 접수와 완료를 구분해야 한다.

확인 응답은 메시지를 지워도 되는 시점을 알린다

소비자가 메시지를 받자마자 확인 응답을 보내면, 실제 작업 전에 종료됐을 때 메시지가 큐에서 사라질 수 있다. 반대로 작업이 끝난 뒤 확인하면 메시지를 잃을 위험은 줄지만 중복 가능성이 생긴다.

1. 이메일 작업 수신
2. 이메일 발송 성공
3. 확인 응답 전 소비자 종료
4. 큐가 같은 메시지를 다시 전달

4번은 메시지를 잃지 않기 위한 정상적인 재전달일 수 있다. 이 구조는 보통 “최소 한 번 전달”을 제공하며, 소비자는 같은 메시지를 여러 번 받을 수 있다고 가정해야 한다.

작업 ID가 중복 실행을 구분한다

메시지마다 고유한 작업 ID를 두고, 소비자는 실제 부수효과를 만들기 전에 이미 성공한 ID인지 확인할 수 있다.

작업 ID 7 수신
  → 완료 기록 없음
  → 이메일 발송
  → 작업 ID 7 완료 기록

작업 ID 7 재수신
  → 완료 기록 있음
  → 다시 발송하지 않음

확인과 실제 변경이 서로 다른 저장소에서 따로 실행되면 그 사이에도 장애가 날 수 있다. 가능한 경우 업무 변경과 작업 완료 기록을 같은 원자적 경계에 두거나, 외부 서비스에도 같은 중복 방지 키를 전달해야 한다.

원본 변경과 메시지 생성 사이에도 빈틈이 있다

주문을 데이터베이스에 저장한 뒤 이메일 메시지를 큐에 넣는다고 하자. 주문 저장은 성공했는데 큐 전송 전에 서버가 종료되면 주문은 있지만 이메일 작업은 없다.

주문 저장 성공
   ↓ 여기서 종료
큐 메시지 전송 실패

반대 순서로 큐부터 보내면 주문 저장이 실패했는데 존재하지 않는 주문의 메시지가 실행될 수 있다. 한 방법은 주문과 함께 “보낼 작업” 기록을 같은 데이터베이스 트랜잭션에 남기고, 별도 전달자가 그 기록을 큐로 옮기는 것이다. 중요한 것은 기술 이름보다 두 성공 사이의 실패 지점을 없애지 말고 명시적으로 다루는 것이다.

재시도는 잠시 쉬고 제한해야 한다

외부 이메일 서비스가 장애인데 즉시 무한 재시도하면 실패한 시스템에 더 큰 부하를 준다. 재시도 간격을 점차 늘리고 최대 횟수를 정해야 한다.

계속 실패한 메시지는 별도 보관소로 옮겨 원인과 입력을 확인할 수 있게 한다. 실패 메시지를 버리지도, 정상 메시지 사이에서 끝없이 반복하지도 않는 경계가 필요하다.

실패 → 잠시 대기 → 재시도
반복 실패 → 별도 실패 보관소 → 확인 후 재처리

병렬 소비자는 메시지 순서를 바꿀 수 있다

여러 소비자가 동시에 작업하면 처리량은 늘지만, 먼저 들어온 메시지가 항상 먼저 끝나지는 않는다. 주문 생성 뒤 취소 메시지가 왔는데 취소가 먼저 처리될 수도 있다.

순서가 중요한 작업은 같은 주문 ID를 같은 처리 흐름으로 보내거나, 소비자가 현재 상태와 버전을 확인해야 한다. 큐 전체의 순서 보장과 특정 키 안의 순서 보장은 다른 문제다.

메시지 형식도 생산자와 소비자의 계약이다

생산자와 소비자는 서로 다른 시점에 배포될 수 있다. 생산자가 새 필드를 추가하거나 의미를 바꿔도 이전 소비자가 메시지를 읽을 수 있어야 한다.

필드를 추가할 때 기본값을 어떻게 해석할지, 삭제한 필드를 언제까지 받을지, 알 수 없는 버전은 실패 보관소로 보낼지를 정해야 한다. 큐는 실행 시간뿐 아니라 배포 시간을 분리하므로 메시지 형식의 호환성이 중요하다.

이해 확인 질문과 답변

큐에 메시지를 넣으면 작업이 완료된 걸까?

아니다. 큐에 안전하게 접수됐다는 뜻이다. 소비자가 실제 작업과 완료 기록까지 끝내야 완료 상태가 된다.

작업 뒤에 확인 응답을 보내면 왜 중복이 생길 수 있을까?

실제 작업은 성공했지만 확인 응답 전에 소비자가 종료될 수 있기 때문이다. 큐는 완료를 모른 채 같은 메시지를 다시 전달한다.

재시도를 하면 결국 성공하니 무한히 해도 될까?

아니다. 영구적으로 잘못된 입력이나 오래 지속되는 장애는 끝나지 않는다. 간격과 횟수를 제한하고 반복 실패를 별도로 보관해야 한다.

여러 소비자를 두면 순서도 그대로 유지될까?

보장되지 않을 수 있다. 작업 시간이 다르면 완료 순서가 바뀐다. 순서가 중요한 키는 같은 처리 흐름으로 묶거나 버전과 현재 상태를 확인해야 한다.

AI에게 이렇게 요청할 수 있다

이메일 작업이 큐에서 소비자에게 전달되고 발송 뒤 확인 응답 전에 소비자가 종료되는 과정을 설명해 줘. 작업 ID로 중복 발송을 막고, 재시도 간격과 한도, 실패 보관소, 사용자에게 접수와 완료를 구분해 보여 주는 방법을 포함해 줘.

메시지 큐를 이해했다면 “뒤에서 처리한다”에서 끝나지 않고, 어느 시점에 접수와 완료를 알리며 중복·누락·순서 변경·반복 실패를 어떤 상태로 다룰지까지 설명할 수 있다.

 

반응형
KEEP READING
카테고리 전체 보기 →

댓글