4. Queue를 둔 이유: 분석 요청을 API 응답과 분리

Queue는 나중에 처리할 작업을 메시지 형태로 보관하고, 별도의 처리자가 꺼내 실행하게 하는 대기열이다.

Queue가 일을 없애거나 무조건 더 빠르게 만들지는 않지만, 사용자가 기다리는 요청 경로에서 일부 작업을 분리하기 때문에 사용자는 응답을 기다릴 필요가 없다. 또한, Queue는 단순히 응답을 기다리지 않아도 되는 작업을 처리하기 위해 사용할 뿐만 아니라 여러 개의 요청들을 한 번에 묶어서 보내어 서버/DB의 부하를 줄이기 위해 사용하기도 한다.

예를 들어, 분석 데이터 이벤트를 생각하면:

사용자 1 ─┐
사용자 2 ─┤
사용자 3 ─┤
...      ├─→ DB
사용자 100┘

Queue가 없다면 이벤트 100개가 들어왔을 때 INSERT가 100번 발생할 수 있다. 반면 Queue Consumer가 100개를 batch로 받아서 처리하도록 하면:

100 events
→ Queue
→ batch [event1, event2, ... event100]
→ 1 INSERT

100 번의 DB 요청을 1번으로 줄일 수 있다. 만약, 1초에 10,000개의 이벤트가 들어와도 DB가 10,000개 요청을 직접 받지 않고 Queue가 받아두고 Consumer가 처리 가능한 속도로 batch 단위로 소비할 수 있다.

Queue는 웹 분석 서비스에서 더욱 빛을 발한다고 볼 수 있다. 왜냐하면, 트래픽이 정말 많은 서비스는 하루에도 수 천, 수 만명이 접속하고 매 접속마다 Queue없이 이벤트를 전송하면 트래픽과 비례하여 부하가 늘어나기 때문이다. 물론, 정확한 수치는 하루 총 접속자 수가 아닌 동시 접속자 수를 따져야 한다.

이러한 특성 때문에 아키텍쳐에 Queue를 포함해서 설계를 진행했다.

일반적인 HTTP 요청의 흐름

일반적인 동기 HTTP 요청에서는 서버가 응답 전에 필요한 작업을 모두 마쳐야 한다.

sequenceDiagram
    participant U as 사용자 또는 클라이언트
    participant S as 서버
    participant D as 데이터베이스
    participant X as 외부 서비스

    U->>S: 요청
    S->>D: 데이터 저장 또는 조회
    D-->>S: 결과
    S->>X: 추가 작업 요청
    X-->>S: 결과
    S-->>U: 최종 응답

회원 가입을 예로 들면 다음과 같다.

  1. 사용자가 가입 정보를 보낸다.
  2. 서버가 계정을 저장한다.
  3. 서버가 외부 이메일 서비스에 환영 이메일 발송을 요청한다.
  4. 서버가 알림 설정을 만든다.
  5. 서버가 사용자에게 응답한다.

이 흐름에서 사용자의 대기 시간은 응답을 보내기 전까지의 전체 작업 경로에 영향을 받는다.

사용자 대기 시간
≈ 계정 저장 + 이메일 서비스 호출 + 알림 설정 + 각 작업의 네트워크·처리 시간

작업이 순서대로 실행된다면 각 작업 시간의 합에 가깝다. 일부 작업을 병렬로 실행했다면 가장 오래 걸리는 병렬 작업을 포함한 전체 실행 경로(critical path) 가 대기 시간을 결정한다.

따라서 “가장 느린 작업이 항상 대기 시간을 결정한다”는 표현은 정확하지 않다. 다만 오래 걸리는 작업은 전체 응답 시간을 크게 늘리는 주요 원인이 될 수 있다.

Queue를 사용했을 때의 흐름

Queue를 사용하면 서버는 요청에 꼭 필요한 작업을 처리한 뒤, 나머지 작업을 메시지로 Queue에 넣는다. 이후 Consumer 또는 Worker가 그 메시지를 받아 후속 작업을 처리한다.

sequenceDiagram
    participant U as 사용자 또는 클라이언트
    participant S as 서버
    participant Q as Queue
    participant W as Worker 또는 Consumer
    participant D as 데이터베이스
    participant X as 외부 서비스

    U->>S: 요청
    S->>D: 핵심 데이터 저장
    D-->>S: 완료
    S->>Q: 후속 작업 메시지 발행
    Q-->>S: 발행 성공
    S-->>U: 응답

    Q->>W: 메시지 전달
    W->>X: 후속 작업 실행
    X-->>W: 결과

회원 가입 예시는 다음처럼 바뀐다.

  1. 사용자가 가입 정보를 보낸다.
  2. 서버가 계정을 저장한다.
  3. 서버가 “환영 이메일 발송”과 “알림 설정 생성” 메시지를 Queue에 넣는다.
  4. Queue 발행이 성공하면 서버가 사용자에게 응답한다.
  5. Worker가 나중에 메시지를 받아 후속 작업을 처리한다.

이때 사용자가 받은 응답은 보통 다음을 의미한다:

"핵심 작업은 끝났고, 후속 작업은 Queue에 맡겨졌다." (이는 후속 작업까지 모두 끝났다는 뜻과는 다르다.)

두 흐름의 차이

구분일반적인 동기 HTTP 요청Queue를 사용하는 요청
응답 기준응답 경로의 작업이 완료된 뒤 응답핵심 작업과 메시지 발행이 성공한 뒤 응답
사용자의 대기후속 작업 완료까지 기다릴 수 있음후속 작업을 기다리지 않음
후속 작업 결과응답 전에 확인 가능나중에 완료되거나 실패할 수 있음
외부 서비스 장애요청 지연 또는 실패로 이어질 수 있음별도 재시도 정책으로 처리 가능
트래픽 급증처리 대상 시스템에 즉시 부하가 집중됨Queue에 대기한 뒤 처리 가능한 속도로 소비 가능
데이터 반영 시점요청 완료 시점에 함께 반영하기 쉬움일부 데이터는 나중에 반영되는 eventual consistency가 될 수 있음

Queue를 사용하면 사용자가 더 빨리 응답을 받는 경우가 많다. 단, 이는 뒤로 미룬 작업이 요청의 성공 조건에 포함되지 않고, Queue 발행 자체가 정상적으로 끝난다는 전제에서만 성립한다.

예를 들어 이메일 발송을 Queue로 넘기면 사용자는 이메일 발송 완료를 기다리지 않아도 된다. 반면 계정 저장처럼 가입 성공의 핵심 조건인 작업은 응답 전에 완료되어야 한다.

Queue를 사용하면 무엇이 이득일까?

사용자가 기다려야 하는 작업을 줄일 수 있다

반드시 수행해야 하지만 사용자가 완료까지 기다릴 필요는 없는 작업은 Queue로 분리할 수 있다.

즉, “이 작업이 끝나야 사용자가 다음 행동을 할 수 있는가?”를 기준으로 나눈다. 그렇지 않다면 후속 작업으로 분리해 응답을 더 빠르게 줄 수 있다.

순간적인 요청 폭증을 완충할 수 있다

flowchart LR
    A["짧은 시간에<br/>많은 요청 발생"] --> Q["Queue<br/>작업을 대기시킴"]
    Q --> W["Worker가 처리 가능한<br/>속도로 소비"]
    W --> D["저장소 또는 외부 서비스"]

    style Q fill:#fef3c7,stroke:#d97706,stroke-width:2px

Queue는 요청 유입 속도와 실제 처리 속도 사이의 버퍼 역할을 한다. 다만 Queue의 용량과 소비 속도에는 한계가 있으므로, 작업이 계속 더 빠르게 쌓이면 대기 시간도 늘어난다. Queue는 부하를 없애는 것이 아니라, 부하를 조절 가능한 대기열로 바꾸는 것이다.

재시도와 실패 분리가 가능하다

많은 Queue 시스템은 처리 실패 시 재시도와 Dead Letter Queue를 설정할 수 있다.

flowchart LR
    M["작업 메시지"] --> W["Worker 처리"]
    W -->|성공 후 확인| A["완료"]
    W -->|실패| R["설정된 정책에 따라 재시도"]
    R --> W
    R -->|재시도 한도 초과| D["Dead Letter Queue<br/>별도 확인 및 재처리"]

    style D fill:#fee2e2,stroke:#dc2626

이 구조는 일시적인 네트워크 오류나 외부 서비스 장애를 요청 처리와 분리하는 데 도움이 된다. 하지만 재시도 횟수, 간격, Dead Letter Queue 사용 여부는 Queue 제품과 설정에 따라 달라진다.

책임을 분리할 수 있다

구성 요소담당하는 일
API 서버요청 검증, 핵심 작업, 메시지 발행
Queue메시지 보관과 Consumer 전달
Worker시간이 걸리는 후속 작업 실행

이렇게 나누면 API 서버는 요청 응답에 집중하고, Worker는 배치 처리·외부 호출·변환처럼 무거운 작업에 집중할 수 있다.

언제 Queue를 사용해야 할까?

아래처럼 반드시 수행해야 하지만 즉시 완료될 필요는 없는 작업에 적합하다.

상황Queue가 적합한 이유
이메일·문자·푸시 발송발송 완료를 사용자가 기다릴 필요가 없음
이미지·영상 변환처리 시간이 길고 자원 사용량이 큼
파일 업로드 후 썸네일 생성업로드 성공과 파일 가공을 분리 가능
외부 API 동기화일시적 실패를 재시도 정책으로 다룰 수 있음
대량 데이터 처리유입량과 처리량의 차이를 버퍼링할 수 있음
로그·분석 이벤트 처리수집 응답과 저장·집계를 분리 가능
여러 독립 후속 작업하나의 요청에서 모두 기다릴 이유가 없음

판단을 위한 질문은 다음과 같다.

이 작업이 실패하면 원래 요청 자체를 실패로 알려야 하는가?

언제 Queue를 사용하면 안 될까?

사용자가 지금 바로 확정된 결과를 받아야 하거나, 다음 단계가 그 결과에 의존한다면 Queue만으로 처리하면 안 된다.

상황이유
로그인 성공 여부사용자는 즉시 성공 또는 실패를 알아야 함
권한 확인다음 동작 전에 즉시 판단되어야 함
재고 확인 후 주문 확정현재 상태를 기준으로 즉시 확정해야 함
결제 승인 결과사용자는 결제의 최종 상태를 바로 알아야 함
즉시 반영이 필요한 화면 동작늦게 반영되면 사용자 경험이 깨질 수 있음

결제는 대표적인 혼합 사례다.

flowchart LR
    P["결제 요청"] --> A["결제 승인<br/>동기 처리"]
    A -->|승인| R["즉시 성공 응답"]
    A -->|거절| E["즉시 실패 응답"]
    R --> Q["영수증 발송·운영 알림<br/>Queue 처리"]

    style A fill:#dcfce7,stroke:#16a34a
    style Q fill:#fef3c7,stroke:#d97706

결제 승인 결과는 사용자가 즉시 알아야 하므로 동기 처리한다. 반면 영수증 이메일 발송과 운영 알림은 결제 승인 뒤 Queue로 분리할 수 있다.

분석 서비스를 가볍게 예로 들면

방문 이벤트를 수집하는 서비스에서는 사용자가 페이지를 보는 동안 수집 요청이 자주 발생한다.

flowchart LR
    T["방문 이벤트"] --> A["수집 API"]
    A --> Q["Queue"]
    Q --> W["분석 Worker"]
    W --> E["이벤트 저장"]
    W --> S["세션 계산"]
    W --> R["집계 갱신"]

수집 API는 입력이 유효한지 확인하고 메시지를 Queue에 넣은 뒤 응답한다. 이후 Worker가 이벤트 저장, 세션 계산, 집계 갱신을 처리한다.

이렇게 하면 수집 요청은 후속 분석 처리 완료를 기다리지 않는다. 대신 대시보드의 일부 수치는 잠시 뒤 반영될 수 있으며, 이 지연을 사용자 경험과 데이터 정확성 요구사항에 맞게 관리해야 한다.

Queue를 사용할 때 알아야 할 점

메시지가 한 번만 처리된다고 가정하면 안 된다

Queue 제품에 따라 메시지는 한 번 이상 전달될 수 있다. 예를 들어 Cloudflare Queues는 기본적으로 at-least-once delivery를 제공하므로 드물게 같은 메시지가 중복 전달될 수 있다. 따라서 Worker는 같은 작업을 여러 번 받아도 결과가 중복되지 않도록 설계해야 한다. 이를 멱등성(idempotency)이라고 한다. Cloudflare의 delivery guarantees 문서

메시지 발행과 후속 작업 완료는 다른 일이다

Queue에 메시지를 넣는 데 성공해도 Consumer 처리까지 성공했다는 뜻은 아니다. Consumer 실패, 재시도, 처리 지연을 관찰할 수 있어야 한다.

순서가 중요하다면 별도 설계가 필요하다

Queue를 사용한다고 해서 모든 메시지가 항상 원하는 순서로 처리된다고 가정하면 안 된다. 순서가 중요한 작업은 순서 보장 방식, 단일 처리 키, 버전 번호, 또는 재정렬 전략을 별도로 설계해야 한다.

관찰 지표가 필요하다

최소한 아래는 확인할 수 있어야 한다.

정리

Queue는 요청을 빠르게 끝내기 위한 도구이면서, 후속 작업을 별도로 관리하기 위한 처리 경계다.

  1. 핵심 작업과 후속 작업을 분리한다.
  2. 사용자가 기다리는 응답 경로를 줄일 수 있다.
  3. 트래픽 급증을 대기열로 완충한다.
  4. 실패한 후속 작업에 재시도 정책을 적용할 수 있다.
  5. 중복 처리, 지연 반영, 순서 문제를 고려해 설계해야 한다.

Cloudflare Queues