AWS Messaging
SQS, SNS, EventBridge, Kinesis and MSK solve different problems that look alike. This page explains each from first principles, with the queue settings that cause real incidents (visibility timeout, polling, DLQs, FIFO groups), the fan-out and routing patterns, the stream services, how Lambda consumes all of them, how to secure, monitor and pay for them, and a decision guide for choosing.
Which AWS Service Is Which
AWS does not have one messaging service, it has several, and they correspond closely to the ideas from page 01 and the brokers in pages 02 and 05. Amazon SQS is a managed queue, Amazon SNS is managed publish/subscribe, Amazon EventBridge is a serverless event bus with content-based routing, Amazon Kinesis Data Streams is a managed log, and Amazon MSK is managed Apache Kafka. They are usually combined: SNS in front of several SQS queues, EventBridge rules that target a Kinesis stream, Lambda reading from any of them.
| SQS | SNS | EventBridge | Kinesis Data Streams | MSK | |
|---|---|---|---|---|---|
| Model | Queue | Topic (pub/sub) | Event bus, rules | Stream of shards | Kafka topics and partitions |
| Delivery to consumer | Consumer polls | Service pushes | Service pushes | Consumer polls (or push with enhanced fan-out) | Consumer polls |
| Stores messages | 60 s to 14 days (default 4 days) | No (retries only) | No (optional archive) | 24 h default, up to 365 days | Kafka topic retention |
| Replay | No (message is deleted) | No (FIFO topics can archive and replay) | Archive and replay | Yes, from a position | Yes, offsets |
| Ordering | FIFO queues, per message group | FIFO topics, per message group | No ordering guarantee on the classic bus | Per shard (per partition key) | Per partition |
| Competing consumers | Yes, built in | n/a | n/a | One reader per shard per application | Consumer groups |
| You manage | Nothing | Nothing | Nothing | Shard count (provisioned mode) | Brokers, partitions (not on Serverless) |
- SNS and the EventBridge bus deliver and forget. If a subscriber is down for longer than the retry policy allows, the event is dropped unless you attached a dead-letter queue. When a consumer must survive downtime, put an SQS queue (or a stream) between the producer and the consumer.
- Chapters 02 to 04 go deep on SQS because its settings cause most production incidents. Chapters 05 to 07 cover SNS, EventBridge, Kinesis and MSK. Chapter 08 is the decision guide, 09 the Lambda glue, 10 operations, 11 Java code and common mistakes.
Queue Types, Limits, Visibility, Polling and Batching
Amazon SQS stores messages redundantly and lets any number of producers and consumers use a queue without you running a broker. The two things to understand first are that delivery is at-least-once and that a received message is only hidden, not removed.
| Standard queue | FIFO queue | |
|---|---|---|
| Throughput | Very high, nearly unlimited API calls per second per action | 300 transactions per second per API action per partition; up to 3,000 messages per second with batching (300 calls x 10); higher with high throughput mode |
| Ordering | Best effort, can arrive out of order | Strict order within a message group |
| Duplicates | At-least-once: occasional duplicates | Deduplication within a 5-minute window on send; processing is exactly-once only if you delete before the visibility timeout expires |
| Name | Any | Must end in .fifo |
| Message group ID | Optional (enables fair queues) | Required on every message |
| Use for | Work queues, buffering, fan-out targets where order does not matter | Per-entity ordering, no tolerated duplicates (payments, inventory per SKU) |
The FIFO figures are from the SQS quotas page. High throughput mode raises the limits by Region (the page lists, for example, up to 70,000 transactions per second in US East (N. Virginia), US West (Oregon) and Europe (Ireland), and lower numbers elsewhere). Look up your Region before sizing a FIFO design.
| Item | Value | Note |
|---|---|---|
| Message size | 1 byte to 1,048,576 bytes (1 MiB) | Larger payloads: Extended Client Library (up to 2 GB via S3) |
| Retention | Default 4 days; 60 seconds to 14 days | Per queue attribute MessageRetentionPeriod |
| Visibility timeout | Default 30 s; 0 s to 12 hours | 12 hours counted from first receive, extensions do not reset it |
| Delay (message timer / delay queue) | 0 s default; up to 15 minutes | Hides a message from consumers after it is sent |
| Batch size | Up to 10 messages per batch call | Total batch payload also capped at 1 MiB |
| Long polling wait | Up to 20 seconds | WaitTimeSeconds |
| Message attributes | Up to 10 per message | |
| In-flight messages | About 120,000 standard; 120,000 FIFO | Received and not yet deleted. See chapter 04 for FIFO groups |
| Message group ID length | 128 characters | Alphanumeric and punctuation |
| Backlog (messages waiting) | Unlimited |
When a consumer receives a message, SQS starts the visibility timeout (30 seconds unless you change it). Other consumers cannot see the message until it ends. If the consumer calls DeleteMessage first, the message is gone. If not (crash, exception, slow processing), the message becomes visible and is delivered again.
ChangeMessageVisibility sets a new timeout for one received message, measured from the moment of the call, so a long job can send a heartbeat that keeps extending it. Setting it to 0 releases the message immediately (a polite way to give up). The ceiling is 12 hours from the first receive. For work that needs longer, split it or use AWS Step Functions.
ReceiveMessage returns a new receipt handle, and a delete should use the handle from the most recent receive. The first consumer holds an older handle, so its delete may not remove the messagemaxReceiveCount the message goes to the DLQ even though the job works, just slowlyChangeMessageVisibility. With Lambda, use at least six times the function timeout (chapter 09)Short polling (WaitTimeSeconds = 0, the default) | Long polling (WaitTimeSeconds 1 to 20) | |
|---|---|---|
| Servers queried | A weighted random subset | All servers |
| Returns | Immediately, possibly empty even if messages exist | As soon as a message is available, empty only after the wait expires |
| Empty responses | Frequent on a quiet queue (each is a billed request) | Rare |
| Latency for a new message | Next poll | Immediate |
Use long polling everywhere. Set the queue attribute ReceiveMessageWaitTimeSeconds to 20 so that even a careless consumer long-polls, and watch the NumberOfEmptyReceives metric to find consumers that poll wastefully.
SendMessageBatch,DeleteMessageBatchandChangeMessageVisibilityBatchhandle up to 10 entries per call. They cut the number of requests (and the request-based bill) by up to ten.- A batch call can succeed overall while some entries fail. Always check the
Failedlist in the response and retry only those entries. - You cannot grant permissions to the batch actions separately: permission for
SendMessage,DeleteMessageorChangeMessageVisibilitycovers the batch version. - A message timer (
DelaySecondson one message) or a delay queue (queue-level default) hides new messages for up to 15 minutes. It is not a scheduler for later than that: use EventBridge Scheduler (chapter 06). - Messages over 1 MiB: the SQS Extended Client Library for Java (and for Python) writes the payload to Amazon S3 and sends a small message holding the S3 reference, up to 2 GB. It works only with synchronous clients, and the consumer must also use the library.
- Short polling returns empty responses on a quiet queue, and every empty response is a request you pay for. It also queries only a sample of servers, so a message can be missed on one call and appear on the next. Long polling at 20 seconds is the right default for nearly every consumer.
Dead-Letter Queues and Redrive
A poison message (one that always fails) would otherwise be received, fail, reappear, and repeat forever, burning compute and hiding behind healthy traffic. A dead-letter queue (DLQ) is an ordinary SQS queue that the source queue moves a message to once it has been received too many times. It turns an endless retry loop into a visible, inspectable pile.
maxReceiveCountis how many times a consumer may receive the message before SQS moves it. A value of 1 sends a message to the DLQ after one failed attempt, so one transient error is fatal. The Lambda guide recommends at least 5 for queues read by Lambda.- The DLQ must be in the same account and Region as the source queue, and the queue type must match (FIFO source needs a FIFO DLQ, standard needs standard). Create the DLQ first.
- A redrive allow policy on the DLQ controls which source queues may use it: allow all (the default),
byQueuewith up to 10 source queue ARNs, ordenyAll. - Retention: on a standard queue the message keeps its original enqueue timestamp, so a message that spent 3 days in a queue with 4-day retention has 1 day left in the DLQ. Set the DLQ retention longer than the source (up to 14 days) or poisoned messages vanish before you look.
- Messages moved to a DLQ keep their encryption state; an unencrypted source stays unencrypted in an encrypted DLQ.
The policy is a JSON document stored as a string inside the attribute map, which is why the quotes are escaped twice. Terraform and CloudFormation hide this, the CLI does not.
After you fix the bug, move the dead letters back. SQS has a managed task for it, which replaced the old copy-and-delete scripts. The three API actions are StartMessageMoveTask, ListMessageMoveTasks and CancelMessageMoveTask.
- By default messages go back to the queue they came from. You may name another destination of the same type, and set a maximum velocity (messages per second) so the redrive does not swamp the consumer.
- A redrive task runs at most 36 hours; an account can have up to 100 active tasks.
- Redriven messages are new messages: new message ID, new enqueue time, fresh retention. Redriven messages interleave with live traffic in the destination.
- IAM: the caller needs
sqs:StartMessageMoveTask,sqs:ReceiveMessage,sqs:DeleteMessageandsqs:GetQueueAttributeson the DLQ, andsqs:SendMessageon the destination. If a queue policy restricts access to a VPC endpoint, add anaws:CalledViaLastexception so the redrive service can act. - Moving between FIFO queues replaces the original deduplication ID with the original message ID, so the DLQ does not drop two independent messages that happened to share a deduplication ID.
maxReceiveCountApproximateNumberOfMessagesVisible greater than 0 for the DLQ- AWS documents that a DLQ on a FIFO queue can break the exact order of messages. The message that fails is moved aside and the next message in its group proceeds, so the group is processed with a gap. For ordered workflows where a gap is worse than a stall, do not use a DLQ, or stop the consumer and fix the data.
For a standard queue with maxReceiveCount above 3, a message received three or more times without being deleted is moved to the back of the queue, and ApproximateAgeOfOldestMessage then reports the age of the next message instead. A stuck poison message therefore does not make that metric spike. Rely on the DLQ metric and NumberOfMessagesReceived versus NumberOfMessagesDeleted, not on age alone.
FIFO Queues: Message Groups, Deduplication and Fair Queues
A FIFO queue gives you ordering per message group, not per queue. Every message must carry a MessageGroupId. Messages in the same group are delivered in the order they were sent, and while one message of a group is in flight, no later message of that group is handed out. Different groups proceed in parallel. So the group ID is the unit of ordering and the unit of parallelism: a design decision, not a detail.
- Receiving: one
ReceiveMessagecan return up to 10 messages from the same group, in order. You cannot ask for a particular group. You cannot get the next message of a group until the received ones are deleted or become visible again. - A failing message blocks its group. The group waits until the message is deleted or expires (or is moved to a DLQ, see chapter 03). Other groups keep flowing.
- Producers: if several producers share a group ID, SQS orders their messages by arrival. For strict per-producer order, give each producer its own group ID.
- Deduplication: a message with the same
MessageDeduplicationIdas one already accepted within a 5-minute window is acknowledged but not delivered again, even if the first one was already received and deleted. Provide the ID yourself, or enable content-based deduplication and let SQS hash the body. - Producer retries are safe. If
SendMessagetimes out, resend with the same deduplication ID. ForReceiveMessage, a retry can reuse the same receive request attempt ID.
| Choice of group ID | Ordering you get | Parallelism | Typical use |
|---|---|---|---|
orderId, customerId, accountId | Per entity | As many lanes as active entities | The normal choice |
| A few fixed values (region, shard number) | Per bucket | Capped at that count | Bounded, even load |
| One constant | Total order | One message at a time | Rare: a true global sequence |
| A random UUID per message | None (FIFO is wasted) | Maximum | Use a standard queue instead |
FIFO limits are counted in API requests per partition, not messages. Without high throughput mode each partition handles 300 transactions per second per action, or 3,000 messages per second if every call is a batch of 10. High throughput mode raises that (by Region), and SQS spreads message groups over partitions, so many distinct group IDs let it scale. The in-flight limit for FIFO is 120,000 messages. The CloudWatch metric ApproximateNumberOfGroupsWithInflightMessages shows how many lanes are actually busy: a big backlog with a low value means too few groups or too few consumers.
A different problem: many tenants share one standard queue and one tenant floods it, so everyone else's messages wait behind the flood (the noisy neighbour problem, measured as dwell time). Amazon SQS fair queues address this without any queue setting: on a standard queue, producers set MessageGroupId to a tenant identifier. SQS watches how many in-flight messages each tenant has, labels a tenant with a disproportionate share as noisy, and prefers messages from the other tenants when it hands messages out.
- It does not rate-limit the noisy tenant: if consumers have spare capacity and nothing else is waiting, the noisy tenant is served at full speed.
- Throughput stays as high as a standard queue and there is no limit on the number of tenants. Ordering is not guaranteed (this is a standard queue).
- The
MessageGroupIdhere means "tenant", not "ordered lane". AWS recommends setting it on every message of a fair queue. - Metrics include
ApproximateNumberOfNoisyGroupsand the...InQuietGroupsvariants (for exampleApproximateAgeOfOldestMessageInQuietGroups), which exclude the noisy tenants so you can alarm on what other tenants experience.
- With a single group ID a FIFO queue behaves like a one-lane road: only one message is in flight at a time, so adding consumers changes nothing and the backlog grows. Symptom: many idle consumers, a growing
ApproximateNumberOfMessagesVisible, andApproximateNumberOfGroupsWithInflightMessagesstuck at 1. Choose a group ID that matches the entity whose events must be ordered.
Topics, Subscriptions, Filtering and the SNS-to-SQS Fan-Out
Amazon SNS is push-based publish/subscribe. A publisher sends one message to a topic; SNS copies it to every subscription and delivers it to that subscription's endpoint. Subscribers can be Amazon SQS queues, AWS Lambda functions, HTTP/S endpoints, Amazon Data Firehose delivery streams, and (outside this page's focus) email, SMS and mobile push. SNS does not store messages for later reading, so durability on the consumer side comes from the endpoint, which is why the standard pattern is a queue per consumer.
| Item | Value |
|---|---|
| Message size | Default 262,144 bytes (256 KiB); raise up to 1,048,576 bytes (1 MiB) with the topic attribute MaximumMessageSize; larger via the SNS Extended Client Libraries (up to 2 GB) |
| Batch publish | PublishBatch: up to 10 entries per request |
| Topics per account | 100,000 standard; 1,000 FIFO |
| Subscriptions per topic | 12,500,000 standard; 100 FIFO |
| Filter policies | 200 per topic; 10,000 per account |
| Publish rate | Per-account, per-Region (for example 30,000 messages per second in N. Virginia); see the quotas page for yours |
A filter policy on a subscription lists attribute names and the values it accepts; SNS delivers only matching messages. By default the policy scope is MessageAttributes; set the subscription attribute FilterPolicyScope to MessageBody to match on fields inside a JSON body. Operators include exact match, prefix, suffix, anything-but, numeric comparisons and ranges, exists, IP address match and case-insensitive equality. A property you do not list in the policy is ignored.
- Filtering is evaluated by SNS before delivery, so unmatched messages cost the subscriber nothing. Different attribute names are AND-ed, several values for one name are OR-ed.
- Changes to a filter policy can take up to 15 minutes to take full effect (eventual consistency). Do not assume a deploy is instant.
- On FIFO topics, filtering makes delivery at-most-once for the filtered-out copies, by definition.
Subscribing a queue needs two things: a subscription (protocol sqs, endpoint the queue ARN) and a queue policy that lets the SNS service principal send to that queue. Scope the policy with aws:SourceArn (and optionally aws:SourceAccount) so only your topic can write to the queue.
By default SNS wraps the message in a JSON envelope (fields such as Type, MessageId, TopicArn, Message, Timestamp, Signature, UnsubscribeURL) and your consumer must unwrap Message. Setting the subscription attribute **RawMessageDelivery to true** strips the SNS metadata and delivers the original body as the SQS message body. With raw delivery on SQS, message attributes are carried across as SQS message attributes; for HTTP/S and Firehose endpoints, attributes are not sent.
The same wiring in Terraform or CloudFormation is the same three resources: a queue, a queue policy, a subscription. Keep them in one stack so the policy always names the right topic ARN.
| Endpoint type | Retry schedule (default policy) | Total |
|---|---|---|
| SQS, Lambda, Firehose (AWS managed) | 3 immediate; 2 at 1 s; 10 with exponential backoff 1 to 20 s; then 100,000 at 20 s | 100,015 attempts over 23 days |
| HTTP/S, SMTP, SMS, mobile push (customer managed) | 2 at 10 s; 10 with backoff 10 to 600 s; then 38 at 600 s | 50 attempts over about 6 hours |
- Only the HTTP/S policy can be customised (the total retry time cannot exceed 3,600 seconds). Retries use jitter.
- Retries cover server-side errors only. A client-side error (the Lambda function was deleted, the queue policy no longer allows SNS) is not retried.
- When the policy is exhausted, or on a client error, the message is discarded unless the subscription has a dead-letter queue: an SQS queue in the same account and Region (FIFO queue for a FIFO topic subscription). An encrypted DLQ needs a customer managed key whose key policy lets the SNS service principal use it.
- Failed deliveries do not change the subscription's state.
A FIFO topic keeps order per message group and deduplicates by deduplication ID within five minutes, like a FIFO queue. It carries the group ID to subscribed SQS FIFO queues (the group ID is not passed to standard queues). The per-topic default is 3,000 messages per second or 20 MB per second when FifoThroughputScope is Topic, with at most 300 messages per second inside one message group. A FIFO topic allows far fewer subscriptions than a standard one (100 per topic). Use it with SQS FIFO queues for ordered fan-out, such as every consumer seeing price updates for one product in order.
- A consumer written against the producer's JSON suddenly fails because the body is now an SNS envelope with the real payload as an escaped string in
Message. Either unwrapMessagein the consumer or enableRawMessageDeliveryon the subscription, and keep the choice documented. Mixing both styles in one queue is a classic source of parse errors.
Event Buses, Rules, Targets, Scheduler and Pipes
Amazon EventBridge routes events (JSON documents describing something that happened) from sources to targets according to rules that match on event content. Where SNS fans a message to everyone subscribed, EventBridge looks inside the event and decides, per rule, whether to forward it. AWS services publish their own events (an EC2 state change, an S3 object created) to the account's default bus automatically, which is why EventBridge is also the glue for operational automation.
The EventBridge guide now describes a Custom Event Bus (subscribers instead of rules, events retained for 1 to 365 days, ordered delivery per event group, deduplication, cross-account sharing through AWS RAM, PutEvents and PutRawEvents) next to Custom Event Bus - Classic, the rules-and-targets bus most existing accounts use. AWS says to start new applications with the new bus, and both remain available. This chapter teaches the rule and target model because it is what you will find in existing systems, and the matching, transformation, retry and DLQ ideas carry over. Check the EventBridge user guide for which model your Region and account offer.
An event has the envelope fields version, id, detail-type, source, account, time, region, resources and a free-form detail. An event pattern has the same shape as the event and matches if every field you list matches. Each value in a pattern is an array (OR), different fields are AND-ed.
- A rule belongs to one bus. One event can match several rules; each rule has up to 5 targets.
- A pattern is limited to 2,048 characters. Rules using wildcards are limited to 30 per bus. The default is up to 300 rules per bus in most Regions.
- Test patterns in the EventBridge Sandbox before attaching them to a rule.
- Targets include Lambda, SQS, SNS, Kinesis, Step Functions, another event bus, and API destinations (HTTPS endpoints with managed authentication and rate limiting).
- An input transformer reshapes the event before the target sees it: you define up to 100 variables with JSON path (
$.detail.orderId), then write an input template that uses<orderId>. Reserved variables includeaws.events.rule-nameandaws.events.event.ingestion-time. Use it to send a target only what it needs. - Retries: by default EventBridge retries a failed delivery for 24 hours, up to 185 times, with exponential backoff and jitter. Errors that cannot succeed (missing permission, target deleted) are not retried. Both limits are configurable per target.
- DLQ: attach an SQS queue as a dead-letter queue to a target, otherwise an event whose retries are exhausted is dropped.
- The classic bus has no ordering guarantee and at-least-once delivery, so targets must be idempotent (chapter 10).
- An archive stores events from one source bus, optionally filtered by a pattern, for a number of days you choose (indefinitely by default). Replay re-sends archived events to the bus that received them, which is how you recover from a bug or test a new rule against real traffic. Allow about 10 minutes after the events arrived before replaying, and note that EventBridge adds a managed rule so replayed events are not archived again.
- The schema registry stores schemas (AWS event schemas, schemas discovered from live traffic, and custom ones) so developers can generate code bindings instead of hand-writing event classes.
- EventBridge Scheduler is a separate serverless scheduler: cron and rate expressions, or one-time schedules, with flexible time windows, retries and a maximum retention for failed triggers. Delivery is at-least-once. Templated targets exist for SQS, SNS, Lambda and EventBridge, and universal targets reach more than 270 services and over 6,000 API operations. Use it for "run this once at 09:00 next Tuesday", something SQS delay (15 minutes at most) cannot do.
- EventBridge Pipes is for point-to-point integration: one source, optional filter, optional enrichment, one target. Sources are DynamoDB streams, Kinesis streams, Amazon MQ brokers, Amazon MSK, SQS queues and Apache Kafka. Source order is preserved, and you are charged only for events that pass the filter. A pipe replaces the small "read, filter, call, forward" Lambda you would otherwise write.
| SNS | EventBridge (rules and targets) | |
|---|---|---|
| Routing | Filter policy per subscription on attributes or body | Rule with rich patterns on the whole event |
| Typical sources | Your own publishers | AWS services, SaaS partners and your own code |
| Targets per fan-out | Very large subscription counts | Up to 5 targets per rule, up to 300 rules per bus by default |
| Throughput focus | High publish rates, large fan-out | Many event types and rules, moderate rates (regional quotas apply) |
| Replay | FIFO topic archive and replay | Archive and replay on the bus |
| Schedules | No | EventBridge Scheduler |
| Pick it when | Same message to many consumers, mobile or email delivery, high rate | Routing by content, reacting to AWS events, cross-account event buses, schedules |
- EventBridge is built for events and routing, and the account quotas for
PutEventsand invocations are per Region. A firehose of telemetry belongs in Kinesis, MSK or SNS-to-SQS. Use EventBridge for the business events and AWS events that need content-based routing.
Kinesis Data Streams and Amazon MSK
Kinesis Data Streams (KDS) is AWS's native log. Like Kafka (page 02) it keeps ordered records for a retention period and lets many applications read them independently, but it is a different API, with shards instead of partitions and no brokers to run. Amazon MSK is the other route: managed Apache Kafka, with the Kafka API, clients and ecosystem unchanged.
- A stream is a set of shards. Each record has a partition key, a data blob and a sequence number assigned by Kinesis. The partition key is hashed to choose the shard, so all records with the same key go to the same shard and keep their order there.
- Each shard supports up to 1 MB/s or 1,000 records/s for writes and 2 MB/s (and 5 read transactions per second) for reads. Stream capacity is the sum of its shards.
- A record's data payload can be up to 10 MiB (before base64); the quotas page notes that the design target is intermittent large records of 1 to 10 MiB using burst capacity, not a steady stream of them.
- Hot shards: a skewed partition key (one customer sending most traffic) overloads one shard while others idle. Symptom:
WriteProvisionedThroughputExceededon the stream even though total throughput looks low. Fix with a higher-cardinality key or a key salt.
| Provisioned mode | On-demand mode | |
|---|---|---|
| Capacity | You choose the shard count and change it with UpdateShardCount (or split and merge) | Kinesis scales shards for you |
| Throughput | Per shard: 1 MB/s in, 2 MB/s out | New streams start at 4 MB/s write and 8 MB/s read, and scale to the account limits (10 GB/s write and 20 GB/s read in N. Virginia, Oregon and Ireland; 200 MB/s and 400 MB/s in other Regions; see the quotas page) |
| Billing shape | Per shard-hour plus per data put | Per throughput used (see the pricing page) |
| Switching | You can switch a stream between modes twice in 24 hours | |
| Pick it when | Steady, predictable load you want to cost precisely | Spiky or unknown load, no desire to manage shards |
On-demand has two flavours in the current docs, Standard and Advantage; Advantage allows up to 50 registered enhanced fan-out consumers per stream instead of 20. Details and pricing are on the Kinesis pages.
- Retention is 24 hours by default and can be raised to 365 days (8,760 hours) with
IncreaseStreamRetentionPeriod(and lowered, to a minimum of 24 hours, withDecreaseStreamRetentionPeriod). - Shared-throughput readers call
GetRecords; all of them divide a shard's 2 MB/s and its 5 read transactions per second. Add a third and fourth application and each gets less, and latency rises. - Enhanced fan-out gives each registered consumer a dedicated 2 MB/s per shard, pushed over HTTP/2 with
SubscribeToShard, so readers do not compete. Up to 20 registered consumers per stream (50 with On-demand Advantage). It is billed separately. - The Kinesis Client Library (KCL) is a Java library (other languages through the MultiLangDaemon) that handles worker coordination, load balancing, checkpointing in a DynamoDB lease table, failover, and shard splits and merges. Delivery is at-least-once, so process idempotently. KCL 2.0 and later use enhanced fan-out. AWS recommends the latest version; the docs call out upgrading from KCL 2.6.0 or earlier to 2.6.1 or later.
In provisioned mode you change capacity by splitting a hot shard into two or merging two cold ones (or with UpdateShardCount). The parent shard stops accepting writes and its data stays readable until retention ends; new records go to the child shards. The KCL processes all parent data before the children, which preserves per-partition-key order across a reshard. A hand-written consumer must do the same.
Watch GetRecords.IteratorAgeMilliseconds (how far behind the reader is), ReadProvisionedThroughputExceeded, WriteProvisionedThroughputExceeded and IncomingBytes.
PutRecords can succeed as a call while individual records fail (throttling on a hot shard). The response's failedRecordCount and per-record errorCode tell you which entries to retry, and retries can reorder records, so do not depend on cross-retry ordering.
| Option | What it is | Notes (MSK guide, checked 2026-10-31) |
|---|---|---|
| MSK Provisioned, Standard brokers | You pick broker type, count per Availability Zone (minimum one broker per AZ) and storage | Closest to self-managed Kafka without the servers. AWS runs the KRaft controllers at no extra cost |
| MSK Provisioned, Express brokers | Brokers with pay-as-you-go storage that scales automatically, no storage sizing | AWS describes up to 3x throughput per broker, faster scaling and recovery than Standard. Three-AZ only, select instance sizes, no maintenance windows. Supported on Kafka 3.6, 3.8, 3.9 and 4.2; KRaft from 3.9 |
| MSK Serverless | A cluster type where AWS provisions and scales capacity and manages partitions | Throughput-based pricing. IAM access control only (Kafka ACLs are not supported). Available in a limited list of Regions |
MSK runs open-source Apache Kafka, so producers and consumers from pages 03 and 04 work unchanged. Related managed pieces are MSK Connect (Kafka Connect) and MSK Replicator (cross-cluster replication for provisioned clusters). The set of supported Kafka versions changes, so check the "supported Apache Kafka versions" page before choosing.
MSK is the right answer when you already use Kafka (clients, Kafka Streams, Connect, a team that knows it) or you need Kafka's ecosystem and semantics, including consumer groups and transactions. KDS is simpler when you live in AWS and want nothing to operate.
- In provisioned mode the shard count caps both write and read throughput, and adding shards later changes which shard a key maps to, so for a short while one key's records straddle a parent and a child shard. Plan the key, watch
IteratorAgeMilliseconds, and reshard before consumers fall behind retention. If you do not want to think about it, on-demand mode exists for that reason.
Kinesis vs MSK vs SQS (and SNS, EventBridge)
The services overlap, so choose by the question you are really asking: is each message a job to be done once (queue), a fact other systems may want to react to (topic, bus) or an ordered history to be read, re-read and processed as a stream (log)?
| Question | SQS | Kinesis Data Streams | MSK |
|---|---|---|---|
| Each message is processed by one worker, then it is done | Best fit | Awkward (no per-message ack, a failure blocks the shard) | Awkward |
| Several independent applications read the same data | Needs SNS or EventBridge in front to copy it | Yes, shared or enhanced fan-out | Yes, consumer groups |
| Replay history after a bug or for a new consumer | No | Yes, within retention (to 365 days) | Yes, within topic retention |
| Per-key ordering at high volume | FIFO queues, limited by group and API throughput | Yes, per shard by partition key | Yes, per partition |
| Retry one bad message later without blocking others | Yes, visibility timeout and DLQ | No: it blocks the shard; bisect and skip | No: needs a retry topic |
| Delay or schedule delivery | Delay up to 15 minutes | No | No |
| Stream processing (windows, joins) | No | Managed Service for Apache Flink, KCL | Kafka Streams, Flink |
| Existing Kafka clients, tools or connectors | No | No (different API) | Yes |
| Operations burden | None | Low (shards unless on-demand) | Higher (brokers, partitions, upgrades) except Serverless |
| Message size limit | 1 MiB (2 GB with the Extended Client) | Up to 10 MiB per record | Per Kafka and broker settings |
- Default to SQS for asynchronous work: it is the least to operate, scales without thinking, and its visibility timeout, DLQ and redrive handle failure well.
- SNS plus one SQS queue per consumer when several teams need the same event and each needs its own retries, backlog and failure isolation.
- EventBridge when the routing depends on event content, when the events come from AWS services or SaaS, or when you need schedules and cross-account delivery.
- Kinesis when you need an ordered, replayable stream with several readers and prefer AWS-native, serverless operation.
- MSK when you need Kafka itself: its ecosystem, its consumer-group and transaction semantics, or portability with a Kafka estate elsewhere (pages 02 to 04).
- They compose: a common shape is producers to Kinesis or MSK for the raw stream, a Lambda or Flink job turning it into business events on EventBridge, and SNS to SQS delivering those events to services.
- A team picks Kinesis for a job queue, then finds that one poison record stops its shard, there is no per-message delay or DLQ semantic, and parallelism is capped by shards. Conversely, a team builds an event-history store on SQS and discovers messages are gone once consumed. Decide queue versus log first, product second.
- SQS and SNS bill mostly per request (and for data transfer), so batching and long polling reduce cost directly. EventBridge bills per event (plus extra for archives, Pipes and Scheduler). Kinesis provisioned bills per shard-hour plus data, on-demand per throughput, and enhanced fan-out is extra. MSK bills per broker and storage, or per throughput on Serverless and Express storage. Prices differ by Region and change, so use the AWS pricing pages and the pricing calculator with your own message counts rather than a rule of thumb.
Event Source Mappings for SQS, Kinesis and MSK
When a Lambda function consumes a queue or stream, Lambda itself does the polling. An event source mapping is the Lambda-managed resource that reads from the source, gathers a batch and invokes your function synchronously with it. You write a handler that receives a list of records, not a poller.
- Batch size: up to 10,000 for a standard queue, 10 for FIFO. Over 10 requires a batch window (
MaximumBatchingWindowInSeconds) of at least 1 second; the window applies to standard queues only. A batch is also bounded by the 6 MB synchronous payload limit, so you may get fewer records than the batch size. - Visibility timeout: the function timeout must not exceed the queue's visibility timeout (Lambda checks), and AWS recommends six times the function timeout (plus the batch window) so retries after throttling do not outrun it.
- DLQ: put the redrive policy on the source queue (an SQS DLQ), not on the Lambda function. Set
maxReceiveCountto at least 5. - Encrypted queue: add
kms:Decryptto the function's execution role. The managed policyAWSLambdaSQSQueueExecutionRolecovers the queue permissions.
Concurrency scaling (standard queues): Lambda starts with five concurrent batches and adds up to 300 more concurrent invocations per minute, to a maximum of 1,250 for one mapping. When traffic is low it scales back toward five (and as few as two). Maximum concurrency on the mapping caps how many instances the queue may use, protecting a shared account pool or a downstream database. Provisioned mode (a minimum and maximum number of dedicated event pollers) scales faster and higher at extra cost, and cannot be combined with maximum concurrency. If you set reserved concurrency on the function, leave at least five, or the mapping is throttled.
FIFO: Lambda delivers messages in order per message group, and a failure holds the group until retries are done. Different groups run in parallel.
Without it, one bad record fails the whole batch: every message, including the good ones, returns to the queue and is processed again. Enable ReportBatchItemFailures in the mapping's FunctionResponseTypes, catch exceptions per record, and return the IDs of the ones that failed. Everything not listed is treated as successful and deleted.
- Return an empty list for full success. If the handler throws, the whole batch counts as failed.
- For a FIFO queue, stop at the first failure and report all remaining messages in the batch too, or you break the order.
- With the feature on, Lambda does not scale polling down when invocations fail, which keeps throughput up while a few messages are bad.
- The Powertools for AWS Lambda Batch Processor (Python, Java, TypeScript, .NET) implements this protocol for you.
| Kinesis Data Streams | MSK (and self-managed Kafka) | |
|---|---|---|
| Ordering and scaling unit | One batch in flight per shard; ParallelizationFactor 1 (default) to 10 allows several concurrent batches per shard (same partition key order kept) | Partitions; event pollers scale with backlog (provisioned mode: a poller handles up to 5 MB/s or 5 concurrent invocations) |
| Reader type | Shared (polls each shard about once per second) or enhanced fan-out consumer for dedicated throughput | Kafka consumer group managed by Lambda |
| Batching | Batch size and window (default window 0 s, so invoke as soon as records arrive); batch limited by 6 MB | Window 0 to 300 s |
| On error | By default the shard is blocked: the batch is retried until it succeeds or the records expire, so one bad record stalls the shard | Retries until success or record age, configurable |
| Controls | BisectBatchOnFunctionError, MaximumRetryAttempts, MaximumRecordAgeInSeconds, DestinationConfig on-failure destination, ReportBatchItemFailures (return the sequence number) | Maximum retry attempts (default -1, infinite; 10 if you set an on-failure destination), maximum record age, split batch on error, partial batch response, Kafka topic as on-failure destination |
| Lag metric | Lambda IteratorAge | Lambda OffsetLag |
- Starting position: with
LATEST, events can be missed while the mapping is created or updated; useTRIM_HORIZONif you must not miss any. - Bisect on error halves a failing batch to isolate the bad record; combined with
ReportBatchItemFailuresit bisects at the returned sequence number. - A stream consumer must configure retry limits and an on-failure destination, otherwise a single poison record can block a shard until it expires from the stream. This is the biggest operational difference from SQS, where the DLQ is the default escape hatch.
- Lambda rejects a mapping whose function timeout exceeds the queue visibility timeout, but a timeout that merely equals it still causes duplicates when a batch is retried after throttling. Set the visibility timeout to 6x the function timeout plus the batch window, and expect the occasional duplicate anyway: handlers must be idempotent (next chapter).
Security, Idempotency, Monitoring and Cost
SQS access is the union of two policy systems: identity-based IAM policies attached to the caller, and the queue policy attached to the queue (a resource-based policy). A cross-account caller or an AWS service needs the queue policy to allow it. ListQueues can only be allowed in an IAM policy; every other SQS action supports resource-level permissions, so name the queue ARN.
| Role | Needs | Where |
|---|---|---|
| Producer | sqs:SendMessage on the queue ARN | Producer role (IAM policy) |
| Consumer | sqs:ReceiveMessage, sqs:DeleteMessage, sqs:ChangeMessageVisibility, sqs:GetQueueAttributes | Consumer role (IAM policy) |
| SNS topic delivering to a queue | sqs:SendMessage for principal sns.amazonaws.com, conditioned on aws:SourceArn = the topic ARN | Queue policy |
| EventBridge rule targeting a queue | sqs:SendMessage, via an execution role (RoleArn on the target) that EventBridge assumes (trust: events.amazonaws.com) | IAM role on the target |
| Lambda reading a queue | Managed policy AWSLambdaSQSQueueExecutionRole; add kms:Decrypt for an encrypted queue | Function execution role |
| DLQ redrive | sqs:StartMessageMoveTask, ReceiveMessage, DeleteMessage, GetQueueAttributes on the DLQ; SendMessage on the destination | Operator role |
Policies have size limits (8,192 bytes, 20 statements, 50 principals, 10 conditions per the quotas page), so a queue shared by dozens of topics needs a wildcard condition on aws:SourceArn or a different design.
- A subscription is confirmed but nothing arrives, because the queue policy does not allow the topic. This is a client-side error: SNS does not retry it, and it is discarded unless the subscription has a DLQ. Check
NumberOfNotificationsFailedon the topic and add a DLQ to every important subscription.
| SSE-SQS | SSE-KMS | |
|---|---|---|
| Keys | SQS-managed keys | AWS managed key alias/aws/sqs or your own customer managed KMS key |
| Extra setup | None | Key policy and IAM must allow producers and consumers (kms:GenerateDataKey, kms:Decrypt) |
| Control and audit | Limited | Key policy, rotation and CloudTrail on key use |
| Cost and limits | No KMS calls | KMS requests (reduced by the data key reuse period: default 5 minutes, 1 minute to 24 hours) and KMS throttling at high rates |
| Works with SNS to SQS | Yes | Only with a customer managed key whose key policy grants the SNS service principal GenerateDataKey and Decrypt |
- SQS has server-side encryption enabled by default on newly created queues. It encrypts the message body only: queue name and attributes, message ID, timestamp and message attributes are not encrypted.
- Only messages sent after encryption is enabled are encrypted; the existing backlog is not re-encrypted.
- All requests to an encrypted queue must use HTTPS and Signature Version 4, and anonymous send or receive is rejected.
- A queue encrypted with the default AWS managed key cannot invoke a Lambda function in a different account. Use a customer managed key for cross-account Lambda.
- Kinesis, SNS and EventBridge (custom bus) support encryption at rest with KMS too; check each service's page for the key-policy details.
SQS standard, SNS, EventBridge, Kinesis (KCL) and Lambda retries are all at-least-once, and visibility timeouts, redrive, replay and ESM retries create duplicates on purpose. FIFO deduplication helps only within its 5-minute window and only on the send side. Correctness therefore comes from the consumer:
- Derive an idempotency key from the message (an order ID plus event type, or the message ID) and record it in the same transaction as the side effect (a unique constraint, or a DynamoDB conditional write that fails if the key exists).
- Prefer naturally idempotent operations: set a field to a value, upsert by key, rather than increment or append.
- For Lambda, the Lambda docs point to Powertools for AWS Lambda, which provides an idempotency utility, and a Batch Processor for partial failures. It is a convenience, not a requirement; the pattern above works without it.
- Use the same idea for external calls: pass an idempotency key to the payment or email provider so a retried message does not charge or mail twice.
| Service | Metric | Meaning and use |
|---|---|---|
| SQS | ApproximateNumberOfMessagesVisible | Backlog waiting for a consumer. Scale consumers on it; alarm > 0 on a DLQ |
| SQS | ApproximateAgeOfOldestMessage (seconds) | How long the oldest message has waited: the "are we keeping up" signal. Caveat: poison messages are excluded after repeated receives (chapter 03) |
| SQS | ApproximateNumberOfMessagesNotVisible | In flight. A high steady value means stuck or slow consumers or visibility timeouts that are too long |
| SQS | NumberOfMessagesSent, NumberOfMessagesReceived, NumberOfMessagesDeleted | Received far above deleted means failures and redelivery |
| SQS | NumberOfEmptyReceives | Wasteful polling (short polling or too many idle consumers) |
| SQS FIFO | ApproximateNumberOfGroupsWithInflightMessages | How many lanes are busy; low with a big backlog means a group bottleneck |
| SNS | NumberOfMessagesPublished, NumberOfNotificationsDelivered, NumberOfNotificationsFailed | Publish volume, delivery success and failure per topic |
| SNS | NumberOfNotificationsRedrivenToDlq, ...FailedToRedriveToDlq | Failures going to the subscription DLQ (and failing to) |
| EventBridge | MatchedEvents, Invocations, FailedInvocations, ThrottledRules | Rule matches, target deliveries, permanent delivery failures, throttling |
| EventBridge | InvocationsSentToDlq, InvocationsFailedToBeSentToDlq | Events going to (or failing to reach) the target DLQ |
| Kinesis | GetRecords.IteratorAgeMilliseconds | How far consumers are behind the tip. Alarm well before retention |
| Kinesis | WriteProvisionedThroughputExceeded, ReadProvisionedThroughputExceeded | Throttled records or reads: add shards, fix a hot key, or use enhanced fan-out |
| Lambda (stream sources) | IteratorAge (Kinesis), OffsetLag (MSK) | Lag of the event source mapping |
| Lambda | Throttles, ConcurrentExecutions | Throttling of the function that reads your queue |
SQS metrics are approximate (a distributed system) and some are emitted only while the queue is active, so alarm on several consecutive data points, not a single one. For MSK, use the cluster metrics in the MSK monitoring documentation (consumer lag is the one you will want), not the Kinesis ones.
- SQS and SNS are request-priced. Cost scales with the number of API calls and messages, so batching (up to 10 per call) and long polling (fewer empty receives) cut the bill, and so does not polling from many idle workers.
- EventBridge is event-priced: every event placed on a bus and delivered counts; archives, Pipes and Scheduler have their own meters. A chatty producer on a bus costs more than the same traffic on SNS.
- Kinesis provisioned is capacity-priced: you pay for shard-hours whether or not data flows, plus data put and enhanced fan-out reads. On-demand trades that for per-throughput pricing.
- MSK is infrastructure-priced (brokers and storage), or throughput-priced on Serverless.
- Big hidden costs are elsewhere: data transfer across AZs and Regions, KMS requests on encrypted high-volume queues, Lambda duration and retries, CloudWatch Logs. Model your real volume in the pricing calculator rather than quoting a per-million figure.
Java SDK v2: A Resilient SQS Worker, and Common Mistakes
Application code for SQS in Java uses the AWS SDK for Java v2: software.amazon.awssdk:sqs, and the SqsClient class. SqsClient.create() uses the default Region and credential provider chain (environment, shared config, container or instance role). The class below was compiled with javac against SDK v2 2.31.0; it was not run against a live queue, so treat it as an exact API reference and test it in a sandbox account.
waitTimeSeconds(20)makes this a long poll; with the loop it costs almost nothing while idle.maxNumberOfMessages(10)is the maximum per receive.messageSystemAttributeNames(APPROXIMATE_RECEIVE_COUNT)returns how many times SQS has delivered the message, useful for logging near the DLQ threshold.- Messages are deleted only after success, in one
deleteMessageBatchcall. A failed message is left alone: the visibility timeout returns it, andmaxReceiveCounteventually moves it to the DLQ. sendMessageBatchreturns per-entry results. Retry entries fromfailed(); do not assume the call is all-or-nothing.- In Spring Boot you would normally use a framework (for example Spring Cloud AWS listeners) instead of a hand-rolled loop. The loop shows exactly what those frameworks do: poll, process, delete, extend.
| Mistake | What you see | Fix |
|---|---|---|
| Visibility timeout shorter than processing time | Duplicate processing, rising NumberOfMessagesReceived, messages reaching the DLQ although the code works | Timeout above worst-case processing; heartbeat with ChangeMessageVisibility; 6x function timeout for Lambda |
| Short polling | Many empty receives, a bigger bill, occasionally "missing" messages | Long polling, 20 seconds |
| No alarm on the DLQ | Failed messages silently expire; discovered days later | Alarm ApproximateNumberOfMessagesVisible > 0 on every DLQ, DLQ retention longer than source |
| Single FIFO message group | Idle consumers, growing backlog, 1 busy group | Group by the entity needing order; many groups |
maxReceiveCount of 1 | One transient error sends good messages to the DLQ | At least 3 to 5; at least 5 for Lambda |
Lambda without ReportBatchItemFailures | One bad message reprocesses the whole batch | Return batchItemFailures |
| Not idempotent | Double emails, double charges after retries and redrive | Idempotency key plus a unique constraint |
| Stream consumer with unlimited retries | One poison record blocks a shard; IteratorAge climbs | Retry limits, bisect, record age limit, on-failure destination |
| SNS without queue policy or DLQ | Subscription "works" but delivers nothing; messages discarded | aws:SourceArn queue policy, DLQ on subscription |
| Hot partition key on Kinesis | Write throttling at low total throughput | Higher-cardinality key or salt |
- A consumer that calls
deleteMessageas soon as it gets the message turns SQS into at-most-once: a crash mid-processing loses the message. Delete only after the work and its side effects are done, and make the work safe to repeat.
Interview Questions and Answers
- Q: Standard vs FIFO queue?
Standard: nearly unlimited throughput, at-least-once, best-effort ordering. FIFO: ordering per message group and deduplication within a 5-minute window, with lower per-partition throughput (300 transactions per second per action, more with batching and high throughput mode). Choose FIFO only when order or duplicate suppression is a real requirement. - Q: What is the visibility timeout and what happens if it is too short?
It hides a received message from other consumers (default 30 s, max 12 h from first receive). If processing outlasts it, the message is delivered again, causing duplicates and extra receives that can send it to the DLQ. Set it above worst-case processing, or extend it withChangeMessageVisibility. - Q: Short vs long polling?
Short polling samples a subset of servers and returns immediately, often empty. Long polling (WaitTimeSecondsup to 20) queries all servers and waits for a message, reducing empty responses, cost and latency. - Q: How does a DLQ work and how do you redrive?
A redrive policy on the source queue names the DLQ andmaxReceiveCount. After that many receives without a delete, SQS moves the message. After fixing the bug,StartMessageMoveTask(console: DLQ redrive) moves messages back to the source or another queue of the same type, at a velocity you can limit. - Q: How do message groups give ordering and how can they hurt throughput?
Messages in a group are delivered one at a time in order. Different groups run in parallel. A single group ID serialises the whole queue, and a failing message blocks its group. - Q: How does FIFO deduplication work?
AMessageDeduplicationId(or a hash of the body with content-based deduplication) identifies a message. A second message with the same ID within 5 minutes is accepted but not delivered. It protects against producer retries, not against consumer-side duplicates. - Q: What is the SNS to SQS fan-out and why use it?
One publish to a topic, a queue subscribed per consumer. Each consumer gets its own durable backlog, retry and DLQ, and a slow consumer does not affect others. Needs a queue policy letting SNS send, and usually raw message delivery to skip the SNS envelope. - Q: What are SNS filter policies?
JSON per subscription that selects messages by attributes (or body, withFilterPolicyScope=MessageBody), so subscribers receive only what they need. Evaluated by SNS before delivery. Changes can take up to 15 minutes to apply. - Q: What happens when an SNS delivery fails?
Server-side errors are retried per the endpoint policy (SQS and Lambda: up to 100,015 attempts over 23 days). Client-side errors are not retried. After exhaustion the message is discarded unless the subscription has a DLQ (an SQS queue). - Q: SNS vs EventBridge?
SNS: high-rate fan-out of the same message to many subscribers with attribute or body filters. EventBridge: content-based routing with rich patterns, AWS and SaaS event sources, input transformation, archive and replay, schedules and cross-account buses, at moderate rates and up to 5 targets per rule. - Q: What are EventBridge Pipes and Scheduler?
Pipes: point-to-point source to target with filtering and enrichment, no glue code. Scheduler: cron, rate and one-time schedules that call targets, with retries and flexible time windows. - Q: Kinesis vs SQS?
SQS is a queue: each message is processed by one consumer and removed, with per-message retry and DLQ. Kinesis is a log: ordered per shard, replayable within retention, read by many applications independently, but a failing record blocks its shard. - Q: Kinesis vs MSK?
Both are logs. Kinesis is AWS-native with shards and no brokers; MSK is managed Apache Kafka with the full Kafka API and ecosystem. Pick MSK to keep Kafka tooling and semantics, Kinesis when you want the simplest AWS-native stream. - Q: What is a shard and what causes a hot shard?
The unit of capacity (1 MB/s or 1,000 records/s in, 2 MB/s out). Records with one partition key land on one shard, so a skewed key concentrates load and throttles writes. Fix with a better key, a salt or more shards. - Q: What is enhanced fan-out?
A registered consumer gets a dedicated 2 MB/s per shard pushed over HTTP/2, instead of sharing the shard's 2 MB/s with otherGetRecordsreaders. - Q: How does Lambda consume SQS?
An event source mapping polls the queue, batches messages (up to 10,000 for standard with a window, 10 for FIFO) and invokes the function. It scales pollers up to 1,250 concurrent invocations, or fewer with maximum concurrency. Failures return the batch unlessReportBatchItemFailuresis used. - Q: What is ReportBatchItemFailures?
A setting that lets the handler returnbatchItemFailureswith the IDs of failed messages, so only those return to the queue. Not listing an ID means success. For FIFO, stop at the first failure and report the rest too. - Q: How do you handle a poison record in a Kinesis Lambda consumer?
Retry limit and maximum record age, bisect the batch, partial batch response by sequence number, and an on-failure destination so the failed batch metadata is saved instead of blocking the shard. - Q: SSE-SQS vs SSE-KMS?
SSE-SQS uses SQS-managed keys with no setup. SSE-KMS uses an AWS managed or customer managed KMS key, with key policy control and audit but KMS calls (reduced by the data key reuse period). SNS to an encrypted queue needs a customer managed key with a policy for the SNS principal. - Q: How do you make consumers idempotent?
Store an idempotency key with the side effect in one transaction (unique constraint or conditional write), prefer upserts, and pass the key to external APIs. Powertools for AWS Lambda has an idempotency utility. - Q: How do you send a payload bigger than 1 MiB through SQS?
The Extended Client Library (Java, Python) stores the body in S3 (up to 2 GB) and sends a reference; both sides must use it, and it supports synchronous clients only. - Q: Which CloudWatch metrics would you alarm on?
DLQApproximateNumberOfMessagesVisible> 0, SQSApproximateAgeOfOldestMessage, KinesisGetRecords.IteratorAgeMilliseconds, throttling metrics, SNSNumberOfNotificationsFailed, EventBridgeFailedInvocations. - Q: Scenario: orders must reach billing, shipping and analytics, each with its own failure handling. Design it.
Order service publishesOrderPlacedto an SNS topic. Three SQS queues subscribe with raw delivery and filter policies, each with a DLQ and DLQ alarm. Consumers (Lambda with partial batch responses, or a worker) are idempotent. Add a subscription DLQ on the topic. Use a FIFO topic and FIFO queues only if per-order ordering is required. - Q: Scenario: a Lambda reading a queue makes duplicates under load. Why?
Visibility timeout too close to the function timeout, throttling, or a whole batch failing on one bad message. Set visibility to 6x function timeout (plus batch window), enableReportBatchItemFailures, limit concurrency, and make processing idempotent. - Q: Scenario: a stream consumer is falling behind. What do you check?
IteratorAgeMilliseconds, per-shard throughput, hot shard, consumer errors blocking a shard, enhanced fan-out for contention, parallelization factor, function duration, then shard count or on-demand mode.
Cheat Sheet and Recap
| Concept | Remember | Value (verified 2026-10-31) |
|---|---|---|
| SQS message size | Bigger needs the Extended Client | 1 MiB (2 GB via S3) |
| SQS retention | Set the DLQ higher than the source | 4 days default, 60 s to 14 days |
| Visibility timeout | Above processing time; heartbeat to extend | 30 s default, up to 12 h from first receive |
| Long polling | Always on | WaitTimeSeconds up to 20 s |
| Batch | Check per-entry failures | Up to 10 per call, 1 MiB total |
| Delay | Not a scheduler | 0 to 15 minutes |
| FIFO throughput | Per partition, per API action | 300 TPS; 3,000 msgs/s batched; high throughput by Region |
| FIFO dedup window | Send-side only | 5 minutes |
| DLQ | Alarm on it, same type, account, Region | maxReceiveCount (at least 5 for Lambda) |
| SNS message size | Topic attribute raises it | 256 KiB default, 1 MiB max (Extended Client beyond) |
| SNS retries | SQS/Lambda: very long; client errors not retried | 100,015 attempts over 23 days (AWS managed endpoints) |
| SNS filter policy | Scope attributes by default; 15 minutes to apply | 200 per topic |
| EventBridge | Rules: up to 5 targets; retry 24 h, 185 times | Archive and replay; Scheduler; Pipes |
| Kinesis shard | 1 MB/s in, 2 MB/s out | Retention 24 h to 365 days |
| Kinesis fan-out | Enhanced fan-out is dedicated per consumer | 20 consumers (50 On-demand Advantage) |
| Lambda + SQS | Visibility 6x function timeout; partial batch | Batch up to 10,000 (FIFO 10); to 1,250 concurrent |
| MSK | Provisioned (Standard, Express) or Serverless | Serverless: IAM auth only |
- SQS = queue, SNS = broadcast, EventBridge = content router, Kinesis/MSK = log. Pick queue vs log first.
- SQS delivers at-least-once and only hides a message when received. Delete after success, set the visibility timeout above processing time.
- Always long-poll, always batch, always have a DLQ with an alarm and a retention longer than the source.
- FIFO ordering is per message group; one group is one lane. Choose the group ID deliberately.
- SNS to SQS gives each consumer a durable backlog. Use raw delivery, a scoped queue policy and a subscription DLQ.
- EventBridge routes by content and handles AWS events, schedules and replay; it is not a high-volume data pipe.
- Streams block on failure. Configure retry limits, bisect and on-failure destinations; watch iterator age.
- Lambda ESM: visibility 6x timeout,
ReportBatchItemFailures, maximum concurrency, idempotent handlers. - Everything is at-least-once. Idempotency is the consumer's job. Encrypt with SSE and mind KMS key policies for SNS and cross-account.
Limits, defaults and behaviours on this page were checked on 2026-10-31 against docs.aws.amazon.com: the SQS Developer Guide (message and FIFO quotas, visibility timeout, polling, DLQ and redrive, fair queues, encryption, CloudWatch metrics), the SNS Developer Guide and General Reference quotas (message size, filter policies, delivery retries, DLQs, FIFO topics), the EventBridge User Guide and Scheduler guide (patterns, retries, archive, Pipes, the new Custom Event Bus), the Kinesis Data Streams guide (retention, capacity modes, quotas, enhanced fan-out, KCL), the MSK Developer Guide (Provisioned, Express, Serverless) and the Lambda Developer Guide (SQS, Kinesis and MSK event source mappings). Not quoted on purpose: prices. The Java samples compile against AWS SDK for Java v2 2.31.0 but were not run against live AWS. Quotas differ by Region and change; re-check the quotas page for yours.
- 07 Event-Driven Patterns - outbox, saga, idempotent consumer and the other patterns built on these services.
- 08 Reliability & Operations - retries, DLQs, backpressure and monitoring in depth.
- Messaging Fundamentals - the delivery guarantees behind at-least-once.
- AWS - the rest of the AWS reference pages.