작업을 비동기로 처리해야 할 때 가장 간단한 선택이 Redis List를 이용한 큐입니다. 이메일 발송, 이미지 변환, 알림 전송 같은 작업을 대기열에 넣고 순서대로 처리할 수 있습니다.
# 왼쪽(앞)에 추가
LPUSH queue "작업1"
LPUSH queue "작업2"
LPUSH queue "작업3"
# 현재 상태: ["작업3", "작업2", "작업1"]
# 오른쪽(뒤)에 추가
RPUSH queue "작업4"
# 현재 상태: ["작업3", "작업2", "작업1", "작업4"]
# 여러 개 한 번에
RPUSH notifications "알림1" "알림2" "알림3"
# 인덱스로 범위 조회 (0부터 시작, -1이 마지막)
LRANGE queue 0 -1 # 전체
LRANGE queue 0 2 # 처음 3개
LRANGE queue -3 -1 # 마지막 3개
# 특정 인덱스 조회
LINDEX queue 0 # 첫 번째
LINDEX queue -1 # 마지막
# 길이
LLEN queue
# 왼쪽에서 꺼내기
LPOP queue # "작업3" 반환 후 삭제
# 오른쪽에서 꺼내기
RPOP queue # "작업4" 반환 후 삭제
# 여러 개 꺼내기 (Redis 6.2+)
LPOP queue 3 # 최대 3개 반환
LPOP/RPOP: List의 양 끝에서 원소를 꺼내는 명령. 꺼낸 원소는 리스트에서 삭제됩니다.
BLPOP과 BRPOP은 리스트가 비어 있으면 데이터가 들어올 때까지 대기합니다.
# 최대 30초 대기 (0이면 무한 대기)
BLPOP queue 30
# 다른 클라이언트가 LPUSH하면 즉시 반환
이를 이용해 별도의 폴링 없이 Worker 프로세스가 작업을 기다릴 수 있습니다.
먼저 넣은 것을 먼저 꺼내는 큐는 RPUSH(뒤에 추가) + LPOP(앞에서 꺼내기)으로 구현합니다.
# Producer: 작업 추가
RPUSH job:queue "send_email:user:1000"
RPUSH job:queue "resize_image:upload:500"
RPUSH job:queue "send_push:device:abc"
# Consumer: 작업 하나씩 처리 (블로킹)
BLPOP job:queue 0
# "send_email:user:1000" 반환 → 처리
RPUSH → [작업C | 작업B | 작업A] → LPOP
↑ 뒤에 추가 ↑ 앞에서 꺼냄
나중에 넣은 것을 먼저 꺼내는 스택은 LPUSH(앞에 추가) + LPOP(앞에서 꺼내기)으로 구현합니다.
LPUSH history "페이지A"
LPUSH history "페이지B"
LPUSH history "페이지C"
LPOP history # "페이지C" (마지막에 방문한 것부터)
알림이나 로그처럼 최근 것만 유지해야 할 때 LTRIM을 씁니다.
# 알림 추가
LPUSH user:1000:notifications "새 댓글이 달렸습니다"
LPUSH user:1000:notifications "팔로워가 생겼습니다"
# 최근 20개만 유지
LTRIM user:1000:notifications 0 19
# 최근 알림 목록
LRANGE user:1000:notifications 0 -1
# 이메일 작업 등록 (Producer)
RPUSH queue:email '{"to":"user@example.com","subject":"가입 완료","template":"welcome"}'
# Worker: 블로킹으로 대기
BLPOP queue:email 0
# 작업 수신 → 이메일 발송 → 다시 BLPOP 대기
여러 Worker가 동시에 BLPOP을 기다리면 Redis가 순서대로 하나씩 분배합니다. 별도의 부하 분산 로직 없이 자연스럽게 병렬 처리가 됩니다.
단순한 작업 큐라면 List로 충분합니다. 다만 List는 꺼낸 작업이 삭제되므로 실패 시 재처리가 어렵습니다. 작업 실패 재시도, 소비자 그룹 관리, 메시지 확인 응답이 필요하다면 Redis Stream을 사용합니다.