Skip to content

비동기 작업 큐와 생산자-소비자 모델

서론

사용자가 "보고서 내보내기" 버튼을 누르고, 30초 동안 빙글빙글 도는 로딩 애니메이션을 바라보며 기다렸습니다 -- 이게 합리적인가요? 하나의 조작이 완료되는 데 몇 초甚至 몇 분이 걸린다면, 사용자를 기다리게 하는 것은 좋은 경험이 아닙니다. 비동기 작업 큐는 이 문제를 해결하는 핵심 아키텍처 패턴입니다 -- 시간이 오래 걸리는 조작을 백그라운드로 보내 처리하고, 사용자에게 즉시 응답을 반환합니다.

이 글에서 배울 내용

이 장을 마치면 다음을 얻게 됩니다:

  • 동기 vs 비동기 비교: 특정 조작을 왜 비동기화해야 하는지, 비동기화가 가져오는 사용자 경험 향상 이해
  • 생산자-소비자 모델: Producer-Consumer 패턴의 핵심 사상과 작업 흐름 파악
  • Worker 풀 메커니즘: 작업이 어떻게 여러 Worker에 분산되어 병렬 처리되는지 이해
  • 신뢰성 보장: 작업 재시도, 멱등성, 데드 레터 큐 등 보장 메커니즘 파악
  • 기술 선택 능력: 주류 비동기 작업 프레임워크의 특징과 적용 시나리오 이해
내용핵심 개념
제 1장비동기가 필요한 이유동기 블로킹 vs 비동기 논블로킹
제 2장생산자-소비자 모델Producer, Queue, Consumer
제 3장Worker 작업 풀동시 처리, 작업 분산
제 4장신뢰성 보장재시도 전략, 멱등성, 데드 레터 큐
제 5장프레임워크 선택Celery, Sidekiq, Bull, RQ

0. 전경도: 사용자를 "기다리게" 하면 안 되는 이유

식당에서 주문한다고 상상해 보세요. 좋은 식당은 주문을 받은 후 즉시 대기 번호를 주고, 자리를 잡거나 휴대폰을 하다가 음식이 완성되면 가져갈 수 있게 합니다. 카운터 앞에 서서 요리사가 요리를 끝내기를 지켜보게 하지 않습니다.

웹 애플리케이션에도 비슷한 "요리" 조작이 많습니다:

  • 이메일/SMS 발송: 타사 API 호출, 몇 초 걸릴 수 있음
  • 보고서/PDF 생성: 대량 데이터 계산, 수십 초 걸릴 수 있음
  • 이미지/비디오 처리: 압축, 트랜스코딩, 워터마크 추가, 몇 분 걸릴 수 있음
  • 데이터 동기화: 크로스 시스템 데이터 동기화, 소요 시간 불확실

비동기 작업의 핵심 사상

시간이 오래 걸리는 조작을 "요청-응답"의 주 흐름에서 분리하여 백그라운드 큐에서 비동기적으로 처리합니다. 사용자가 요청을 제출하면 즉시 "접수 완료, 처리 중"이라는 응답을 받고, 처리가 완료되면 알림, 폴링 또는 WebSocket으로 결과를 통지받습니다.


1. 동기 vs 비동기: 하나의 주문 이야기

사용자가 주문을 제출할 때, 백엔드는 여러 가지 일을 해야 합니다: 재고 차감, 주문 기록 생성, 확인 이메일 발송, 추천 시스템 업데이트, 감사 로그 기록...

동기 모드에서는 이러한 조작이 직렬로 실행되며, 사용자는 모든 조작이 완료될 때까지 기다려야 결과를 볼 수 있습니다. 비동기 모드에서는 핵심 조작(재고 차감, 주문 생성)만 완료하고, 나머지 조작은 큐에 넣어 백그라운드에서 처리합니다.

Synchronous vs Asynchronous Processing
Click the button to compare the two processing modes
User request
Waiting to submit
Server processing
Reserve inventory50ms
Create order100ms
Send confirmation email800ms
Update recommendation system600ms
Write audit log300ms
비교 항목동기 처리비동기 처리
사용자 대기 시간모든 조작의 총 소요 시간핵심 조작만의 소요 시간
시스템 처리량낮음 (스레드가 블로킹됨)높음 (스레드를 빠르게 해제)
실패 영향비핵심 실패가 전체 실패 유발비핵심 실패가 주 흐름에 영향 없음
구현 복잡도단순추가 큐 인프라 필요
데이터 일관성강일관성최종 일관성

언제 비동기를 사용해야 하나요?

세 가지 판단 기준: 오래 걸림 (1-2초 초과), 비핵심 (실패해도 주 흐름에 영향 없음), 지연 가능 (즉시 결과가 필요하지 않음). 이 중 두 가지 이상을 만족하면 비동기화를 고려해야 합니다.


2. 생산자-소비자 모델: 작업의 "조립 라인"

비동기 작업 큐의 핵심은 고전적인 생산자-소비자 패턴(Producer-Consumer Pattern)입니다. 이 패턴에는 세 가지 역할이 있습니다:

  • 생산자(Producer): 작업을 생성하는 쪽, 일반적으로 웹 서버가 사용자 요청을 처리할 때
  • 큐(Queue): 처리 대기 작업을 저장하는 버퍼, 일반적으로 Redis, RabbitMQ 등으로 구현
  • 소비자(Consumer/Worker): 큐에서 작업을 꺼내 실행하는 작업 프로세스
Worker Pool Model
Watch tasks get distributed to different workers
Worker count: 3
Task queue (0)
Queue is empty
Workers
Worker 1
💤 Idle
Completed: 0
Worker 2
💤 Idle
Completed: 0
Worker 3
💤 Idle
Completed: 0
Completed (0)
None yet

큐의 세 가지 가치

  1. 결합 해제: 생산자는 누가 작업을 처리할지 알 필요 없고, 소비자는 작업이 어디서 왔는지 알 필요 없음
  2. 피크 평탄화: 트래픽 급증 시 작업이 큐에 먼저 쌓이고, 소비자는 자신의 속도에 맞춰 처리
  3. 신뢰성: 작업이 큐에 지속되므로 소비자가 다운되어도 작업이 유실되지 않음
구성 요소역할일반적 구현
메시지 미들웨어작업 메시지 저장 및 전달Redis, RabbitMQ, Kafka
직렬화기작업 파라미터 직렬화/역직렬화JSON, MessagePack, Pickle
스케줄러정기 작업 및 지연 작업 관리Cron, APScheduler, node-cron
결과 저장소작업 실행 결과 저장Redis, 데이터베이스, S3

3. 신뢰성 보장: 작업이 "유실"되거나 "중복"되어서는 안 됨

분산 환경에서는 네트워크 지터, 서비스 재시작, 리소스 부족 등의 문제가 언제든 발생할 수 있습니다. 비동기 작업 시스템은 완벽한 신뢰성 보장 메커니즘을 갖추어야 합니다.

가장 핵심적인 두 가지 문제: 작업 유실 (소비자가 처리 중간에 다운됨)과 중복 실행 (작업이 두 번 전달됨).

Task Retry and Backoff Strategies
Simulate the retry process after a task fails
Fixed interval
Every retry waits for the same duration. It is simple, but can cause retry storms.
Delay formula:delay = 2s

신뢰성의 세 가지 핵심

  1. ACK 메커니즘: 소비자가 작업 처리를 완료한 후에만 확인(ACK)을 보내며, 미확인 작업은 재전달됨
  2. 재시도 전략: 작업 실패 후 전략에 따라 재시도, 지수 백오프 + 지터가 모범 사례
  3. 멱등성 설계: 동일한 작업을 여러 번 실행해도 한 번 실행한 것과 효과가 동일함, 고유 ID로 중복 제거
메커니즘해결하는 문제구현 방식
ACK 확인작업 유실처리 완료 후 수동 확인, 타임아웃 미확인 시 재전달
데드 레터 큐(DLQ)반복 실패하는 "독 메시지"재시도 상한 초과 후 데드 레터 큐로 이전, 수동 개입 처리
멱등성중복 실행작업 고유 ID로 중복 제거, 데이터베이스 고유 제약
우선순위 큐작업 기아높은 우선순위 작업 우선 처리, 낮은 우선순위 작업에 의한 블로킹 방지
타임아웃 제어작업 교착최대 실행 시간 설정, 타임아웃 시 자동 종료 후 재시도

4. 프레임워크 선택: 적합한 도구 선택하기

다양한 언어 생태계에는 각각의 비동기 작업 프레임워크가 있으며, 기능 풍부도, 성능, 사용 편의성 면에서 각각 장단점이 있습니다. 프레임워크를 선택할 때 먼저 자신의 기술 스택을 고려하고, 그 다음 프로젝트 규모와 요구사항에 따라 결정하세요.

Popular Async Task Frameworks
Click a framework to inspect the details
Celery
Python
Sidekiq
Ruby
Bull
Node.js
RQ
Python
Kafka Streams
Java/JVM
CeleryPython
The most popular distributed task queue in the Python ecosystem. It supports multiple brokers such as RabbitMQ and Redis, with a broad feature set and active community.
Core features:
Scheduled tasksTask chainsResult backendAutomatic retriesPriority queuesTask routing
Typical scenarios:
Data pipelines, email sending, report generation, machine learning training jobs

선택 가이드

  • Python 프로젝트: 중대형은 Celery, 소형은 RQ
  • Node.js 프로젝트: BullMQ(Bull의 차세대)가首选
  • Ruby 프로젝트: Sidekiq이 거의 유일한 선택
  • Java 프로젝트: Spring 생태계는 Spring Batch, 높은 처리량에는 Kafka Streams
  • Go 프로젝트: Asynq(Redis 기반) 또는 Machinery

프로젝트에서 이미 Redis를 사용 중이라면, Redis 기반 솔루션(Celery+Redis, BullMQ, Sidekiq)이 가장 간단한 시작 방법입니다.


요약

비동기 작업 큐는 백엔드 아키텍처에서不可或缺한 인프라입니다. 시스템이 시간이 오래 걸리는 조작을 우아하게 처리할 수 있게 하여, 사용자 경험을 향상시키는 동시에 시스템 처리량을 높입니다.

이 장의 핵심 포인트를 되돌아보세요:

  1. 비동기화 판단 기준: 오래 걸림, 비핵심, 지연 가능 -- 두 가지 이상을 만족하면 비동기화해야 함
  2. 생산자-소비자 모델: Producer -> Queue -> Consumer, 세 요소가 결합 해제되어 협업
  3. Worker 풀: 여러 Worker가 병렬로 소비하여 처리 능력 향상
  4. 신뢰성 보장: ACK 확인 + 재시도 전략 + 멱등성, 세 가지 모두 필수
  5. 프레임워크 선택: 기술 스택과 프로젝트 규모에 따라 선택, Redis가 가장 일반적인 메시지 미들웨어

더 읽어보기