TIL

BullMQ 사용기 / Redis 클러스터에서 주의할 점

하얀잔디 2025. 9. 25. 23:35

최근에 Node.js 기반 채팅 서버에 비동기 작업 처리(알림 전송, 이미지 처리 등)를 붙일 일이 있었는데,

 

메시지 큐를 도입할까 고민하다가 BullMQ를 선택했습니다. RabbitMQ 같은 별도 브로커를 세우지 않고, 이미 쓰고 있던 Redis만 있으면 돌아가니까 부담이 덜하더라고요.

 

 


 

 

BullMQ란?

BullMQ는 간단히 말해 Redis 위에서 돌아가는 Job Queue 라이브러리입니다.

  • Producer (생산자): “이메일 전송 요청” 같은 작업을 큐에 넣음
  • Worker (소비자): 큐에서 작업을 꺼내 실제 실행

코드도 직관적이에요.

 

// Producer
import { Queue } from 'bullmq'

const emailQueue = new Queue('email', {
  connection: { host: '127.0.0.1', port: 6379 }
})

await emailQueue.add('sendMail', { to: 'test@example.com' })

// Worker
import { Worker } from 'bullmq'

const worker = new Worker('email', async job => {
  console.log('Sending mail to', job.data.to)
})

 

 

Redis 클러스터에서 prefix를 꼭 넣어야 하는 이유

단일 Redis 서버에서는 큰 고민이 없는데, Redis Cluster 환경이라면 얘기가 조금 달라집니다.

 

BullMQ는 내부적으로 Redis key를 여러 개 만듭니다.
예를 들어 email이라는 큐를 만들면 이런 키들이 생겨요.

 

bull:email:id
bull:email:jobs
bull:email:wait
bull:email:active

 

 

여기서 문제는 Redis Cluster의 슬롯(Hash Slot) 때문입니다.

  • 클러스터는 키를 해시해서 0~16383 슬롯에 분산 저장합니다.
  • 그런데 BullMQ가 생성하는 키들이 전부 같은 슬롯에 매핑되지 않으면, 명령어 실행 시 MOVED 에러가 뜰 수 있습니다.

이걸 피하려면 prefix를 지정해서 모든 키가 같은 해시 태그 안에 들어가도록 만드는 게 안전합니다.

 

const emailQueue = new Queue('email', {
  prefix: '{bull}', // 모든 키가 같은 슬롯에 배치되도록 설정
  connection: {
    host: '172.30.11.91',
    port: 16379,
    username: 'default',
    password: '비밀번호'
  }
})

 

 

  • {bull} 처럼 중괄호로 묶어주면, Redis는 괄호 안의 문자열을 기준으로 해시 슬롯을 결정합니다.
  • 이렇게 하면 bull:email:wait, bull:email:active 같은 키들이 전부 같은 슬롯으로 들어가요.

👉 만약 prefix를 안 걸면, 클러스터에서 Job Queue가 제대로 작동하지 않을 가능성이 큽니다.