본문으로 건너뛰기
김신건의 로그

[AWS] SQS: managed queue, FIFO, DLQ

· 수정 · 📖 약 2분 · 956자/단어 #aws #sqs #queue #cloud #messaging
SQS, Simple Queue Service, FIFO Queue, Standard Queue, DLQ, visibility timeout, long polling, Dead Letter Queue

정의

SQS (Simple Queue Service) = AWS 의 완전 관리형 메시지 큐. infinite scale, no provisioning, pay-per-request. 프로듀서와 컨슈머를 비동기로 분리.

Standard vs FIFO

항목StandardFIFO
처리량거의 무한300 msg/s (배치 시 3000/s)
순서best-effort엄격 (group 안)
중복at-least-once (드물게 중복)exactly-once (5분 dedup 윈도우)
URL suffix.amazonaws.com/....fifo 필수
가격저렴약간 비쌈

선택 기준: 순서/중복 허용 가능 = Standard. 결제/주문 등 순서 중요 = FIFO.

흐름

sequenceDiagram
    participant P as Producer
    participant SQS
    participant C as Consumer

    P->>SQS: SendMessage(body)
    SQS-->>P: messageId
    C->>SQS: ReceiveMessage(WaitTimeSeconds=20)
    SQS-->>C: message + receiptHandle
    Note over SQS,C: visibility timeout 시작 (기본 30초)
    C->>C: 메시지 처리
    C->>SQS: DeleteMessage(receiptHandle)

Visibility Timeout

컨슈머가 메시지를 가져간 후 다른 컨슈머에게 숨겨지는 시간.

flowchart LR
    Recv["ReceiveMessage"] -->|"invisible (기본 30s)"| Hidden["처리 중\n다른 consumer 안 보임"]
    Hidden -->|"DeleteMessage 성공"| Done["제거됨"]
    Hidden -->|"timeout 만료"| Visible["다시 visible\n= retry"]
    Visible -->|"maxReceiveCount 초과"| DLQ["DLQ 로 이동"]

설정 원칙: 처리 예상 시간 × 2 + 여유 로 설정. Lambda timeout 과 함께 고려.

# 처리 중 timeout 연장 (최대 12시간)
sqs.change_message_visibility(
    QueueUrl=queue_url,
    ReceiptHandle=receipt_handle,
    VisibilityTimeout=600  # 10분으로 연장
)

DLQ (Dead Letter Queue)

# CloudFormation / CDK 설정
RedrivePolicy:
  deadLetterTargetArn: arn:aws:sqs:ap-northeast-2:123:my-dlq
  maxReceiveCount: 5
  • maxReceiveCount 초과 후 자동으로 DLQ 로 이동
  • 원인 분석 후 StartMessageMoveTask 로 원본 큐에 재처리
  • DLQ 자체에도 DLQ 설정 가능 (중첩 방지)

DLQ 에 메시지 쌓이면 CloudWatch alarm 필수. 무한 재처리 방지.

Long Polling

sqs.receive_message(
    QueueUrl=queue_url,
    WaitTimeSeconds=20,        # long poll (최대 20초)
    MaxNumberOfMessages=10,    # 배치 (최대 10개)
)
  • 메시지 없으면 최대 20초 대기 후 반환
  • short polling (기본 0초) 대비 API 호출 횟수 대폭 감소, 비용 절감
  • 거의 항상 WaitTimeSeconds=20 권장

SQS + Lambda 이벤트 소스

AWS 가 자동으로 poll + batch + invoke + delete 처리.

# SAM / CloudFormation
EventSourceMapping:
  EventSourceArn: arn:aws:sqs:...:my-queue
  FunctionName: my-func
  BatchSize: 10
  MaximumBatchingWindowInSeconds: 5
  FunctionResponseTypes:
    - ReportBatchItemFailures   # 부분 실패 처리

ReportBatchItemFailures: batch 중 일부만 실패 시 해당 메시지만 DLQ 로 이동. 나머지는 정상 처리.

def handler(event, context):
    failures = []
    for record in event['Records']:
        try:
            process(record['body'])
        except Exception:
            failures.append({'itemIdentifier': record['messageId']})
    return {'batchItemFailures': failures}

FIFO + MessageGroupId

sqs.send_message(
    QueueUrl=fifo_queue_url,
    MessageBody=json.dumps(payload),
    MessageGroupId='user-42',           # 같은 group = 순서 보장
    MessageDeduplicationId='unique-id'  # 5분 dedup 윈도우
)
  • 같은 MessageGroupId = 한 컨슈머가 순서대로 처리
  • 다른 MessageGroupId = 병렬 처리 가능
  • ContentBasedDeduplication 활성 시 body hash 로 자동 dedup

배치 처리

# 최대 10개 한번에 전송 (비용 절감)
entries = [
    {'Id': str(i), 'MessageBody': json.dumps(msg)}
    for i, msg in enumerate(messages)
]
sqs.send_message_batch(QueueUrl=queue_url, Entries=entries)
  • SendMessageBatch: 최대 10개, 최대 256KB
  • DeleteMessageBatch: 소비 후 일괄 삭제
  • 배치 API = 단건 대비 API 호출 최대 10배 절감

재시도 전략 설계

flowchart TB
    Recv["메시지 수신"] --> Process["처리"]
    Process -->|"성공"| Delete["DeleteMessage"]
    Process -->|"실패"| Retry{"재시도 횟수\n< maxReceiveCount?"}
    Retry -->|"예"| Timeout["visibility timeout 만료\n다시 visible"]
    Timeout --> Recv
    Retry -->|"아니오"| DLQ["DLQ 이동"]
    DLQ --> Alert["CloudWatch Alarm\n운영자 알림"]
    Alert --> Inspect["원인 분석"]
    Inspect --> Redrive["StartMessageMoveTask\n(재처리)"]

exponential backoff: Lambda + SQS 조합에서 재시도 간격을 늘리려면 visibility timeout 을 처리에서 수동으로 늘림.

import time

def handler(event, context):
    for record in event['Records']:
        receive_count = int(record['attributes']['ApproximateReceiveCount'])
        try:
            process(record['body'])
        except RetryableError:
            # 재시도 횟수에 따라 timeout 연장 (backoff)
            backoff = min(2 ** receive_count * 30, 900)  # 최대 15분
            sqs.change_message_visibility(
                QueueUrl=QUEUE_URL,
                ReceiptHandle=record['receiptHandle'],
                VisibilityTimeout=backoff
            )
            raise

모니터링 / 운영

필수 CloudWatch 메트릭:

메트릭의미alarm 기준
ApproximateNumberOfMessages큐 적체량임계값 초과 시
ApproximateAgeOfOldestMessage가장 오래된 메시지 age처리 지연 탐지
NumberOfMessagesSent발행량급감 시 producer 이상
NumberOfMessagesDeleted처리 완료량급감 시 consumer 이상
# DLQ alarm 예시 (CDK)
new cloudwatch.Alarm(this, 'DlqAlarm', {
  metric: dlq.metricApproximateNumberOfMessagesVisible(),
  threshold: 1,
  evaluationPeriods: 1,
  alarmDescription: 'DLQ 에 메시지 발생',
});

SQS vs Kafka 비교

항목SQSKafka
운영 부담0 (managed)클러스터 관리 필요
처리량무한 (auto)노드 수 비례
Retention최대 14일무제한 (디스크)
ReplayDLQ redrive 만consumer offset 자유 조정
Fan-outaws-sns 와 결합consumer group
순서FIFO group 안에서partition 안에서
비용 구조사용량 비례인프라 비례

선택 기준: AWS only + 단순 큐 + 운영 최소화 = SQS. 영속 + 재처리 + 대규모 throughput + 이벤트 스트리밍 = kafka.

비용

  • $0.40 / 백만 요청 (Standard)
  • $0.50 / 백만 요청 (FIFO)
  • 첫 100만 요청/월 무료
  • 256KB 이상 메시지: 256KB 단위로 청구

비용 최적화:

  • Long polling (WaitTimeSeconds=20) 으로 빈 poll API 호출 최소화
  • 배치 전송/수신으로 API 호출 횟수 절감
  • Lambda 이벤트 소스로 폴링 완전 위임

흔한 함정

WARNING

  1. at-least-once 중복 처리: Standard 큐에서 드물게 중복 발생. consumer 는 반드시 idempotent 하게. idempotency-keys 패턴 활용.
  2. Visibility timeout 너무 짧음: 처리 도중 메시지가 다시 visible 되어 다른 컨슈머가 중복 처리.
  3. DLQ 미설정: 실패 메시지가 무한 재시도, 큐 처리 지연 전파.
  4. FIFO 에서 MessageGroupId 없이 전송: 모든 메시지가 단일 group = 단일 컨슈머 = 300 msg/s 한계.
  5. 배치 Lambda 에서 전체 예외: 일부 실패 시 batch 전체 재시도. ReportBatchItemFailures 설정 필수.

CAUTION

FIFO 큐 이름은 반드시 .fifo suffix. 생성 후 변경 불가. 설계 단계에서 결정 필요.

관련 위키

이 글의 용어 (7개)
[AWS] EventBridge: 이벤트 버스, 스케줄러, partner sourcescloud
정의 EventBridge = AWS 의 통합 event bus. 옛 CloudWatch Events 의 후계. AWS service 이벤트 + custom 이벤트 + SaaS …
[AWS] Lambda: 서버리스 함수, 트리거, 동시성cloud
정의 AWS Lambda = 서버리스 함수 실행. 이벤트 트리거 → 함수 실행 → 결과 / 비동기 처리. 서버 관리 0. 사용 상황 | 상황 | Lambda 적합성 | |---|…
[AWS] SNS: pub-sub 알림, fan-out 패턴cloud
정의 SNS (Simple Notification Service) = pub-sub 메시징. Publisher 가 Topic 에 발행하면 모든 Subscriber 에 동시에 fa…
[Distributed] Kafka: 분산 로그, partition, consumer groupdistributed-systems
정의 Apache Kafka = 분산 commit log. 고처리량 (수백만 msg/s), 영속, 수평 확장. event-driven 아키텍처 의 de facto. 핵심 개념: …
[Distributed] Message Broker 비교: Kafka / RabbitMQ / NATS / SQS / Redis Streamsdistributed-systems
정의 Message Broker = 생산자(Producer)와 소비자(Consumer) 사이에서 메시지를 중계하는 미들웨어. 비동기 통신, 부하 분산, 시스템 디커플링의 핵심. …
[Pattern] Idempotency Keys: 중복 요청 안전 처리distributed-systems
정의 Idempotency = 같은 요청을 N번 보내도 결과가 1번과 동일. 분산 시스템 / 결제 / API 의 안전망. [!IMPORTANT] 네트워크는 항상 timeout /…
[Pattern] Outbox Pattern: DB + 메시지의 원자성distributed-systems
정의 Outbox Pattern = DB 변경 + 메시지 발행 의 원자성 보장. 이중 쓰기 (dual write) 문제 의 표준 해결. 문제: Dual Write | 시나리오 |…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기