AWS MESSAGING & STREAMING

SNS vs SQS vs Kinesis vs MSK vs EventBridge vs RabbitMQ: An Architect's Decision Matrix

Same problem — "move data from A to B" — and AWS gives you six different ways to solve it. Only one is usually right for your shape of the problem.

By Swetha Golla · 8 min read · Senior Application Architect

TL;DR

The setup

Scope note: this is a decision matrix for AWS's own catalog, not a survey of every messaging technology that exists. Self-hosted Kafka, Google Pub/Sub, Azure Service Bus, NATS, Pulsar, and plenty of others solve overlapping problems outside AWS's walls — worth knowing about, out of scope here.

A platform team is replacing a single overloaded RabbitMQ broker that has become the answer to every "how do services talk to each other" question for three years running: order events, fraud signals, audit trails, third-party webhooks, and a slow-growing analytics pipeline all queue through it. It works, until it doesn't — a queue depth spike during a promotion in 2025 backed up every consumer behind it, including ones that had nothing to do with the promotion. The team's instinct is to "move it all to AWS-native," as one service. That instinct is the mistake. These six AWS services solve different shapes of the same-sounding problem, and the broker that's currently drowning is actually the right tool for at least one of the workloads still queuing through it.

SQS — Queue Producer Queue delete on ack — no replay SNS — Fan-out Topic identical copy to every subscriber Kinesis / MSK — Log partitions + replay from any offset EventBridge — Rules Event match routes by content, not identical copies RabbitMQ — Exchange Publisher exch broker-side routing (direct/topic/fanout/headers), no replay

Six AWS services, six verdicts

Click the one you're actually evaluating:

→ Fan-out, not storage

One event needs to reach many independent subscribers — SQS queues, Lambda, mobile push, email/SMS, HTTP endpoints — and you don't need to replay it later. SNS is the AWS-native answer, and it's the standard front door for "one event, many uncoupled consumers": publish once, let SNS push (or fan out to SQS queues) to whoever subscribed.

Watch out: nothing is stored. If a subscriber's endpoint is down when you publish, that specific delivery is gone unless you attached a per-subscription dead-letter queue — and a DLQ catches failed deliveries, not a full replay of everything that was ever published.

→ You need real Kafka, not "Kafka-like"

You already have Kafka clients, Kafka Streams jobs, ksqlDB, or Debezium CDC connectors in production, or you need strict per-partition ordering and full replay via consumer offset reset, at very high sustained throughput, with an ecosystem that assumes the actual Kafka wire protocol. MSK is that, managed — Cisco's Webex team runs 147 TB and roughly 100 billion messages a day across 12 MSK clusters and 66 brokers, a scale that specifically needed Kafka's partition and consumer-group model.

Watch out: "managed" narrows the operational surface, it doesn't remove it — that's an assessment worth stating plainly since it's not the kind of comparison AWS's own marketing makes. You're still designing topics and partition counts, sizing brokers, planning consumer-group rebalances, and running version upgrades yourself; MSK Serverless narrows this but doesn't eliminate it. Of the six services here, that's more operational surface than any of the fully serverless options carry, and more than RabbitMQ's single-broker sizing task too — Kafka's partition/rebalancing model is simply a bigger job to own than a broker instance size.

→ AWS-native replay, without owning Kafka's model

You want a partitioned, replayable log — strict ordering per key, the ability to reset a consumer's iterator to the past and reprocess — but you'd rather AWS handle shard mechanics than run brokers yourself. LaunchDarkly's event-ingestion pipeline scaled from about 1 TB to more than 100 TB a day on Kinesis Data Streams, holding 99.99% availability and 99.99999% durability with end-to-end processing under 30 seconds, specifically because they needed durability, per-consumer isolation, and replay without adopting Kafka.

Watch out: each shard is a hard ceiling — 1,000 records or 1 MiB/s in, 2 MiB/s out — so a hot partition key becomes a bottleneck you shard around, not tune away. On-Demand mode auto-scales shards for you at a cost premium; Provisioned mode is cheaper at steady volume but the resharding is on you.

→ Content-based routing is the whole point

Different consumers care about different slices of the same event stream — a fraud service wants only high-risk-flagged orders, a warehouse integration wants only orders from one region — and you'd rather express that as a rule than as consumer-side filtering. EventBridge's pattern matching (up to 5 targets per rule, input transformers to reshape the payload per target) is built for exactly this, across 20+ native AWS targets plus third-party SaaS event sources.

Watch out: it is a router, not a log. There's no built-in replay — Archive & Replay is a separate, additionally-billed feature, and it can only replay what you explicitly chose to archive. It's also not sized for the sustained multi-GB/s throughput Kinesis or MSK are built for; it optimizes for routing logic, not raw volume.

→ Lift-and-shift, or you need AMQP specifically

You're migrating an existing RabbitMQ deployment and don't want to rewrite producers and consumers written against AMQP client libraries, or you specifically need RabbitMQ features SQS doesn't have — priority queues, complex exchange-based routing (direct/topic/fanout/headers), delayed-message plugins. Amazon MQ for RabbitMQ exists precisely so that migration is "point your existing client at a new endpoint," not "rebuild the messaging layer."

Worth untangling: a single RabbitMQ queue is point-to-point, same as SQS — once one consumer reads and acks a message, it's gone from that queue, so two consumers on the same queue split the work rather than both seeing everything. Fan-out to multiple independent subscribers happens one level up, at the exchange: a fanout or topic exchange copies the message into several separate queues, each with its own consumer(s). So RabbitMQ-the-broker (exchange + queues) is the closer analog to SNS+SQS combined — not to SQS alone, and not to RabbitMQ being "just a queue."

Watch out: there's no serverless tier here. You pick a broker instance size (the mq.m7g family), size its storage, and plan for cluster-mode HA yourself — AWS patches the host and manages failover, but capacity planning is still yours, and there's no native replay once a message is acknowledged.

→ The simplest durable buffer that works

A producer and a consumer group shouldn't be coupled in time — the classic decoupling pattern behind most well-built AWS backends. If you don't need replay, don't need strict global ordering, and just want messages to survive until something processes them, SQS is the least operationally demanding option on this entire list, and it's usually the right default before reaching for anything fancier.

Watch out: it's a queue, not a log — once a message is deleted (or ages out after up to 14 days) it cannot be replayed. And SQS has no native fan-out to multiple independent consumer groups; if several different systems all need the same message, put SNS in front of it.

The comparison matrix

SNSMSKKinesisEventBridgeRabbitMQ
(Amazon MQ)
SQS
Model Pub/sub fan-out (push) Partitioned log, Kafka API (pull) Partitioned log, AWS-native (pull) Serverless event bus, content routing (push) Broker queue, AMQP exchanges Point-to-point queue (pull)
Ordering None (standard); strict on FIFO topics Strict per-partition, by key Strict per-shard, by partition key None guaranteed Per-queue FIFO by default; needs Single Active Consumer for strict order with >1 consumer None (standard); strict per message-group on FIFO
Delivery semantics At-least-once; FIFO topics add dedup At-least-once by default; exactly-once with transactional/idempotent producer At-least-once; consumer owns dedup/offsets At-least-once At-least-once (manual ack + publisher confirms); at-most-once only if you use auto-ack At-least-once (standard); effectively exactly-once processing on FIFO with dedup ID
Retention / Replay None — undelivered messages are gone; DLQ catches failed deliveries, not replay Operator-set (commonly 7+ days, bounded by disk); full replay via offset reset 24h default, extendable to 365 days; full replay via shard iterator None by default; Archive & Replay is a separate paid add-on, replays only what you archived None — message gone once acked, no native replay Up to 14 days retention, no replay — deleted on ack or expiry
Throughput ceiling No fixed headline number — raisable soft account/topic quota Broker/cluster-bound, scales with brokers + partitions (147 TB/day across 12 clusters at Cisco Webex) 1,000 records or 1 MiB/s per shard in, 2 MiB/s out; On-Demand auto-scales, Provisioned needs manual resharding 10,000 PutEvents/sec + 18,750 target invocations/sec (us-east-1 default, raisable) Broker-instance bound (mq.m7g family); vertical + limited cluster-mode scaling, no elastic auto-scale Standard effectively unbounded; FIFO high-throughput up to 3,000 msg/sec per partition batched (300/sec unbatched)
Routing Topic → many subscribers, optional attribute-based filter policies Possible via Kafka Streams/consumer-relay topologies (read → filter → re-produce) — application code, not a broker-native rule engine None — consumers pull from shards; routing logic lives in the consumer app Rich content/pattern-based routing, up to 5 targets/rule, input transformers Exchange types (direct/topic/fanout/headers) route inside the broker Single queue → competing consumers; no native fan-out (pair with SNS)
Operational overhead Near-zero, fully serverless High — topic/partition design, broker sizing, upgrades are yours (MSK Serverless narrows this) Low-medium — shard/capacity planning (or On-Demand to skip it) Near-zero, fully serverless Medium — you size broker instances, plan HA/cluster mode, manage engine upgrades Near-zero, fully serverless
Cost model Per-request + per-delivery (varies by protocol) Per-broker-instance-hour + storage — billed whether idle or busy Per-shard-hour (provisioned) or per-GB (on-demand) + PUT payload-unit charges Per-event published + per-target invocation; no idle cost Per-broker-instance-hour + storage — billed whether idle or busy Per-request; no idle cost, FIFO priced slightly above standard
Ecosystem Deep AWS integration — mobile push, email/SMS, Lambda, SQS fan-out Full Apache Kafka wire compatibility — any Kafka client, Streams, ksqlDB, Debezium works unmodified AWS-native — KCL/KPL, Firehose, Managed Service for Apache Flink 20+ AWS services as native targets/sources, plus SaaS partner event sources Standard AMQP 0-9-1 — broad non-AWS client ecosystem, easiest lift-and-shift from existing RabbitMQ Deep AWS integration, universal SDK support — the default "glue" queue
Event size limit 256 KB 1 MB default (message.max.bytes), operator-tunable 1 MiB per record default, configurable up to 10 MiB (Oct 2025 change) 1 MB per event (raised from 256 KB, Jan 2026) 128 MB per message (all instance types) — though AMQP practice keeps messages far smaller 256 KB standard (up to 2 GB via Extended Client Library, payload in S3)

Every figure above is pulled directly from current AWS documentation or an AWS-published customer case study — see Sources below. Quotas change; verify against the live docs before you design against a specific number. One mapping worth keeping in mind while reading the RabbitMQ column: a single RabbitMQ queue is point-to-point, the same model SQS uses — it's the exchange sitting in front of RabbitMQ's queues that does fan-out, which makes RabbitMQ-the-broker closer to "SNS + SQS combined" than to SQS alone.

Real-world use cases

KinesisLaunchDarkly's event pipeline scaled 1 TB/day to 100+ TB/day, replacing a fragile in-process fan-out with per-consumer isolation and replay. MSKCisco Webex's observability stack moved 147 TB/day off self-managed Kafka onto 12 MSK clusters in six weeks, keeping the partitioning model that scale required. SNS + SQS — the standard AWS fan-out pattern: one topic, one queue per interested consumer, so a slow consumer never blocks the others. EventBridgea bus fed by AWS services plus SaaS partner sources, routing by event content rather than volume. Amazon MQ for RabbitMQ — AWS's documented path for lift-and-shift migration of an existing broker, no producer/consumer rewrite. SQS — the default decoupling buffer under most AWS reference architectures: a web tier drops work, a separately-scaled worker fleet drains it.

RULE OF THUMB

Ask two questions before anything else: do you need replay, and do you need strict per-key ordering? Both yes → Kinesis or MSK. Neither → SQS (add SNS in front only if you need fan-out) is simpler and cheaper. If the actual problem is "route by content to different targets," that's EventBridge, not a throughput question. If you already run RabbitMQ, migrating it as-is beats rebuilding what wasn't broken.

Where I actually stand

The team in the setup above didn't need to replace their RabbitMQ broker — they needed to stop routing everything through one instance of it. The audit trail and analytics pipeline belonged on a log (Kinesis) from day one, because someone was always going to ask "replay last Tuesday" eventually. The webhook fan-out belonged on SNS/SQS, because those consumers never needed to see each other's failures. What was actually fine on RabbitMQ — the order-event routing with its exchange-based rules — stayed on RabbitMQ, just on its own dedicated broker instead of sharing one with everything else. The mistake wasn't the broker they picked three years earlier — RabbitMQ was a reasonable choice at the time, and still is for the workload that kept it. The mistake was answering every later "we need messaging for X" request the same way — bolt it onto the existing broker — instead of asking, each time, which of these models actually fits that workload.

See the decision-advisor POC →

A small CLI that takes your ordering/replay/routing/throughput requirements and walks through which of the six it actually points to.

Code: github.com/swethagolla-eng

Sources & Further Reading