Skip to main content

SQS vs SNS vs EventBridge — AWS Messaging Services Decoded

· 7 min read
Goel Academy
DevOps & Cloud Learning Hub

Your monolith is decomposing into microservices. The Order Service needs to tell the Inventory Service, Payment Service, and Notification Service that a new order was placed. You could make three synchronous HTTP calls and hope none of them time out. Or you could use messaging — fire a message and let each service pick it up independently. AWS gives you three ways to do this, and picking the wrong one leads to lost messages, duplicate processing, or an architecture that fights you at every turn.

Why Message-Driven Architecture?

In a tightly coupled system, Service A calls Service B directly. If B is slow or down, A blocks or fails. In a message-driven system, A drops a message on a queue or topic and moves on. B processes it when it's ready.

Benefits: loose coupling (services don't know about each other), resilience (messages survive service failures), scalability (add consumers to handle load), and observability (queue depth tells you how backed up you are).

SQS — The Queue

Amazon SQS (Simple Queue Service) is a fully managed message queue. One producer sends messages, one consumer processes them. Messages are stored until consumed (up to 14 days).

Standard vs FIFO Queues

FeatureStandard QueueFIFO Queue
ThroughputNearly unlimited300 msg/s (3000 with batching)
OrderingBest effortGuaranteed FIFO
DeliveryAt-least-once (possible duplicates)Exactly-once processing
DeduplicationNot supported5-minute deduplication window
Use caseHigh-throughput decouplingOrder-sensitive workflows
# Create a standard queue
aws sqs create-queue \
--queue-name order-processing \
--attributes '{
"VisibilityTimeout": "60",
"MessageRetentionPeriod": "345600",
"ReceiveMessageWaitTimeSeconds": "20"
}'

# Create a FIFO queue (name MUST end in .fifo)
aws sqs create-queue \
--queue-name order-processing.fifo \
--attributes '{
"FifoQueue": "true",
"ContentBasedDeduplication": "true",
"VisibilityTimeout": "60"
}'

Sending and Receiving Messages

# Send a message to the queue
aws sqs send-message \
--queue-url https://sqs.us-east-1.amazonaws.com/123456789012/order-processing \
--message-body '{
"orderId": "ORD-12345",
"customerId": "CUST-789",
"items": [{"sku": "WIDGET-A", "qty": 3}],
"total": 59.97
}' \
--message-attributes '{
"OrderType": {"DataType": "String", "StringValue": "standard"},
"Priority": {"DataType": "Number", "StringValue": "1"}
}'

# Receive messages (long polling with 20s wait)
aws sqs receive-message \
--queue-url https://sqs.us-east-1.amazonaws.com/123456789012/order-processing \
--max-number-of-messages 10 \
--wait-time-seconds 20 \
--attribute-names All \
--message-attribute-names All

# Delete a message after processing
aws sqs delete-message \
--queue-url https://sqs.us-east-1.amazonaws.com/123456789012/order-processing \
--receipt-handle "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0..."

Visibility Timeout and Dead-Letter Queues

When a consumer receives a message, it becomes invisible to other consumers for the visibility timeout period. If the consumer doesn't delete it in time, the message reappears for another consumer. After N failed attempts, the message moves to a dead-letter queue (DLQ):

# Create the dead-letter queue first
DLQ_ARN=$(aws sqs create-queue \
--queue-name order-processing-dlq \
--attributes '{"MessageRetentionPeriod": "1209600"}' \
--query 'QueueUrl' --output text)

# Get the DLQ ARN
DLQ_ARN=$(aws sqs get-queue-attributes \
--queue-url $DLQ_ARN \
--attribute-names QueueArn \
--query 'Attributes.QueueArn' --output text)

# Set the redrive policy on the main queue (3 retries then DLQ)
aws sqs set-queue-attributes \
--queue-url https://sqs.us-east-1.amazonaws.com/123456789012/order-processing \
--attributes "{
\"RedrivePolicy\": \"{\\\"deadLetterTargetArn\\\":\\\"${DLQ_ARN}\\\",\\\"maxReceiveCount\\\":\\\"3\\\"}\"
}"

SNS — The Topic

Amazon SNS (Simple Notification Service) is a pub/sub messaging service. One publisher sends a message to a topic, and all subscribers receive a copy. It's push-based — SNS delivers to subscribers immediately.

Subscribers can be: SQS queues, Lambda functions, HTTP endpoints, email addresses, SMS numbers, or mobile push.

# Create a topic
TOPIC_ARN=$(aws sns create-topic \
--name order-events \
--query 'TopicArn' --output text)

# Subscribe an SQS queue to the topic
aws sns subscribe \
--topic-arn $TOPIC_ARN \
--protocol sqs \
--notification-endpoint arn:aws:sqs:us-east-1:123456789012:inventory-updates

# Subscribe a Lambda function
aws sns subscribe \
--topic-arn $TOPIC_ARN \
--protocol lambda \
--notification-endpoint arn:aws:lambda:us-east-1:123456789012:function:send-confirmation-email

# Subscribe an email (requires confirmation click)
aws sns subscribe \
--topic-arn $TOPIC_ARN \
--protocol email \
--notification-endpoint ops-team@example.com

# Publish a message
aws sns publish \
--topic-arn $TOPIC_ARN \
--message '{
"orderId": "ORD-12345",
"event": "ORDER_PLACED",
"timestamp": "2025-07-05T10:30:00Z"
}' \
--message-attributes '{
"eventType": {"DataType": "String", "StringValue": "ORDER_PLACED"}
}'

The SQS + SNS Fan-Out Pattern

This is the most common messaging pattern on AWS. SNS broadcasts to multiple SQS queues, and each queue feeds a different service:

                    ┌──► SQS: inventory-queue ──► Inventory Service

Order Service ──► SNS ──► SQS: payment-queue ──► Payment Service

└──► SQS: notification-queue ──► Email Service

Each service processes at its own pace. If the Email Service goes down for an hour, its messages pile up in the queue and get processed when it comes back. No messages lost.

# Subscribe multiple queues to the same topic
for queue in inventory-queue payment-queue notification-queue; do
aws sns subscribe \
--topic-arn $TOPIC_ARN \
--protocol sqs \
--notification-endpoint "arn:aws:sqs:us-east-1:123456789012:${queue}" \
--attributes '{"RawMessageDelivery": "true"}'
done

The RawMessageDelivery attribute sends the raw message body instead of wrapping it in SNS metadata. Essential when your consumers don't want to parse the SNS envelope.

EventBridge — The Event Bus

Amazon EventBridge is the newest and most powerful option. It routes events based on content-based filtering — you define rules that match specific event patterns, and only matching events get delivered to targets.

# Put a custom event on the default event bus
aws events put-events \
--entries '[{
"Source": "com.myapp.orders",
"DetailType": "Order Placed",
"Detail": "{\"orderId\":\"ORD-12345\",\"amount\":59.97,\"region\":\"us-east-1\",\"customerTier\":\"premium\"}",
"EventBusName": "default"
}]'

# Create a rule that matches only premium orders over $50
aws events put-rule \
--name "high-value-premium-orders" \
--event-bus-name default \
--event-pattern '{
"source": ["com.myapp.orders"],
"detail-type": ["Order Placed"],
"detail": {
"customerTier": ["premium"],
"amount": [{"numeric": [">", 50]}]
}
}'

# Add a Lambda target to the rule
aws events put-targets \
--rule "high-value-premium-orders" \
--targets '[{
"Id": "vip-handler",
"Arn": "arn:aws:lambda:us-east-1:123456789012:function:handle-vip-order"
}]'

EventBridge Scheduling

EventBridge can also trigger targets on a schedule — replacing CloudWatch Events (cron):

# Run a Lambda every hour
aws events put-rule \
--name "hourly-cleanup" \
--schedule-expression "rate(1 hour)"

# Run at 2 AM UTC every weekday
aws events put-rule \
--name "nightly-reports" \
--schedule-expression "cron(0 2 ? * MON-FRI *)"

SQS vs SNS vs EventBridge

FeatureSQSSNSEventBridge
PatternQueue (point-to-point)Pub/Sub (fan-out)Event bus (content routing)
DeliveryPull (consumer polls)Push (SNS delivers)Push (rules route events)
OrderingFIFO availableFIFO availableBest effort
FilteringNo (consume all)Attribute-basedContent-based (JSON patterns)
RetentionUp to 14 daysNo retention (fire and forget)Replay up to 24 hours (archive)
TargetsConsumer applicationSQS, Lambda, HTTP, Email, SMS20+ AWS services
ThroughputNearly unlimitedNearly unlimitedSoft limit (adjustable)
SchemaAny formatAny formatSchema registry available
3rd party integrationNoNoSaaS integrations (Salesforce, Zendesk)
Cost (per million)$0.40 (requests)$0.50 (publishes)$1.00 (events)

Decision Framework

Use SQS when: You need reliable, ordered processing with retry and DLQ support. One producer, one consumer. Workload buffering.

Use SNS when: One event needs to reach multiple subscribers. Fan-out to SQS queues, Lambda, email, or HTTP.

Use EventBridge when: You need content-based routing (only certain events go to certain targets), scheduling, cross-account events, or SaaS integrations.

Use SNS + SQS when: Fan-out with reliable processing. SNS broadcasts, each SQS queue buffers for its consumer.

What's Next?

Your services can now communicate asynchronously. But all these services need a front door that distributes traffic efficiently. Next, we'll explore AWS Load Balancers — ALB, NLB, and GWLB — and learn which one to use for HTTP APIs, TCP workloads, and network appliances.


This is Part 13 of our AWS series. The fan-out pattern with SNS + SQS is the bread and butter of AWS microservice architectures — learn it cold.