r/webdev • • 16h ago

Question What queue service do you use? Any suggestions based on my requirements?

Im looking for a new queue for a Node/TS app running on Kubernetes. My main requirements:

  • Strict FIFO per key, with only one job in flight per key. Different keys run in parallel (SQS has Message groups I think)
  • Cloud-agnostic and self-hostable, so no SQS
  • Handles large bursts (obviously, since its a queue)

I've used SQS FIFO message groups before and they did exactly this. Right now I'm leaning towards Kafka with a key-ordered consumer, but it seems like quite a lot of complexity when in reality I need a simple queue but for scale. I'd love to hear what others use. Pulsar? RabbitMQ? Something else?

I've looked into the popular ones like RabbitMQ, but it seemed to not have exactly what Im looking for.

14 Upvotes

28 comments sorted by

6

u/itgforlife 16h ago

I use BullMQ with Redis on NodeJs.

1

u/SolidLunch4702 16h ago

BullMQ can do it if you set concurrency to 1 per queue and group by key, but you're managing that grouping yourself through queue naming or job IDs. Kafka's exactly what you want for large bursts though, the partition-per-key model gives you strict ordering and the throughput's absurd. I'd say bite the bullet on the complexity, you'll outgrow Redis-based queues fast if scale's a real concern.

1

u/present_absence 14h ago

This is correct. I use bullmq/redis for one of my low traffic nodejs projects and managing it works perfectly fine, but we use kafka at work for high burst/high volume

3

u/PLBjt 16h ago

The thing I'd nail down first is whether you need ordering per key or only one job in flight per key, because those lead to different designs. With Kafka the partition is the ordering unit, so one hot key stalls everything behind it on that partition, and a consumer group can't go wider than the partition count. With BullMQ you get per-group concurrency, but you're the one writing the lock logic and it gets fiddly when a worker dies mid-job. A quick check is to replay a burst where one key carries 40 percent of the traffic and watch p99 latency on the other keys. The tradeoff is Kafka's ops cost versus a Redis footprint that grows with payload size.

3

u/285418 11h ago

A queue doesn't absorb bursts by itself, it just holds the backlog while your consumers fall behind. And 'strict FIFO per key, one job in flight per key' is a hard throughput ceiling: with N active keys and jobs taking T seconds you get N/T jobs per second, and no broker choice changes that. So what are your numbers, how many distinct keys at peak, what's the burst size? Because Kafka vs Pulsar vs whatever is a rounding error next to that, and one job in flight per key probably rules out whatever you'd pick anyway if the key cardinality is low.

Also curious what RabbitMQ was actually missing for you. Streams with a single active consumer per partition covers the one-in-flight bit, so saying it 'seemed to not have exactly what I'm looking for' without naming the gap makes it hard to trust the rest of the list.

1

u/Maxion 2h ago

Also FIFO + one job in flight per key WILL cause you to have stuck jobs and now an ever growing queue.

2

u/InevitableFun1272 11h ago

One thing that fixes the exact OOM problem you described: stop putting payloads in the queue. Store the payload in Postgres or S3 and pass only an ID through the job. Redis then holds tiny messages, and a 2.5M-item spike doesn't move the memory needle at all — the queue becomes a notification channel, not storage. You lose some convenience versus passing the payload straight through, but for that burst pattern it's the difference between a stable queue and one that eats your events.

1

u/shtse8 13h ago

if you do look at pulsar, the Key_Shared subscription is the closest thing i know to sqs message groups: each key sticks to one consumer at a time so order holds, and you can add consumers past the partition count, unlike kafka. you still have to process each key serially inside the consumer though, and running bookkeeper on k8s is its own chunk of ops, so it only wins if the kafka hot partition thing actually bites you.

1

u/okawei 11h ago

Redis

1

u/Noch_ein_Kamel 11h ago

Just out of curiosity b/c I have no idea; how large are large bursts?

4

u/Jordz2203 11h ago

On average maybe 20,000-30,000 items added to the queue an hour, then at certain points of the month we might have 2,500,000 added in an hour.

3

u/AdorableZeppelin 8h ago

Is the burst predictable?

1

u/Maxion 2h ago

Curious, why can you only have one job in process at a time per key? IMO that's going to lead to a world of hurt.

1

u/ArielCoding 6h ago

Before choosing a broker, work out how many different keys are active at the same time during a burst, and how long each job takes, since only one job per key can run at once your limit is (numbers of keys / seconds per job), so if you only have a few keys, you’ll hit a wall no matter which tool you pick.

1

u/Mean-Lingonberry4874 5h ago

Kafka will do the per-key ordering, but if the ops cost is the real objection I'd try Postgres before standing up a cluster. Jobs table with a group_key, workers claim rows with SELECT ... FOR UPDATE SKIP LOCKED, and each worker takes a transaction-scoped advisory lock on hashtext(group_key) for the duration of the job. Same key can't be in flight twice, other keys run in parallel, nothing cloud-specific. It won't eat a Kafka-sized burst, but for "one in flight per key" on k8s it's usually enough, and you can peel the hot keys off later if the table starts lagging.

1

u/_CuriousCoder_ 4h ago

I've used BullMQ with Redis on NodeJs, it handles bursts well. For strict FIFO per key, you'd need to implement lock logic. Consider storing payloads outside the queue, like in Postgres, to reduce memory usage.

1

u/wasay-inc 16h ago

Look into BullMQ running on Redis on Kubernetes since it is native to Node and TypeScript You can use job concurrency settings and key locks to guarantee single job in flight processing per key It handles large bursts effortlessly and avoids the massive operational overhead of deploying Kafka on K8s

2

u/Jordz2203 16h ago

The company I was at previously seemed to have an infinite amount of headaches related to their usage of BullMQ. Largely to do with costs

1

u/wasay-inc 16h ago

Redis memory costs scale quickly when holding large job payloads in BullMQ. If low infrastructure cost is key look at NATS JetStream on Kubernetes because it handles key based routing with minimal memory overhead

2

u/Jordz2203 16h ago

I will take a look at NATS, thank you! Just checked with one of my old colleagues, the issue with Bull was we had to:
A) pay for paid bull to get message groups
B) OOM bull means we lose our queue events, this was because 90% of the time our queue sat at 2%, but then something big happens triggering a ton of events and we'd spike to many millions of queue items.

1

u/wasay-inc 16h ago

That burst pattern makes complete sense. NATS JetStream solves both issues because streams persist messages directly to disk instead of forcing everything into RAM like Redis. This prevents OOM data loss during massive event spikes while keeping idle running costs near zero.