AWS SAA-C03: Application Integration, Messaging & Streaming — Study Guide

Part of the AWS SAA-C03 Complete Study Guide. Practice these concepts with verified answers in the AWS/Amazon exam hub, or take timed practice tests on ExamRoll.io.

Amazon SQS: Decoupling, Ordering, and Delivery Semantics

Amazon SQS is a fully managed, pull-based message queue whose primary architectural role is to decouple producers from consumers. A synchronous call chain binds the producer’s latency and availability to every downstream dependency; inserting an SQS queue converts that into an asynchronous handoff. Producers enqueue at whatever rate traffic arrives, and consumers dequeue at the rate they can safely process. This is the canonical fix for write bursts that would otherwise overwhelm an RDS instance — the queue absorbs the burst, and a bounded fleet of consumers drains it at a controlled concurrency, keeping database connection counts in check.

Two queue types exist, and the choice governs both throughput and delivery guarantees.

FeatureStandardFIFO
OrderingBest-effortStrict, per MessageGroupId
DeliveryAt-least-once (duplicates possible)Exactly-once within 5-minute dedup window
ThroughputNearly unlimited300 TPS (3,000 batched); 70,000 with high-throughput mode
Queue nameanymust end in .fifo

Standard queues deliver at-least-once with only best-effort ordering. Duplicates can appear when a consumer fails to delete a message before the visibility timeout expires, or when the distributed backend replays a message across shards. Even if you never see a duplicate in testing, the service is architecturally permitted to redeliver, especially during broker failover. Assuming standard queues will “usually” deliver once is a design defect, not an operational risk — duplicates are guaranteed to occur eventually at scale. Consumer logic must therefore be idempotent: track a MessageId or business key in DynamoDB with a conditional write, use an idempotency key on downstream API calls, or rely on upsert semantics.

FIFO queues provide strict ordering within a MessageGroupId and exactly-once processing via a MessageDeduplicationId (either explicit or a SHA-256 of the body) that suppresses duplicates for a 5-minute window. The MessageGroupId is the pivotal concept: all messages sharing a group ID are delivered strictly in order to a single consumer at a time, while different group IDs can be processed in parallel. For an order-processing system where each customer’s events must be sequential but different customers are independent, use MessageGroupId = customerId. Using a single group ID for everything serializes the entire workload and destroys throughput. Deduplication IDs are the correct primitive for preventing duplicate order creation when a user resubmits a hung checkout: the client generates a deterministic idempotency token (a UUID tied to the checkout session) and SQS discards any duplicate submissions arriving within the window.

PaymentsQueue:
  Type: AWS::SQS::Queue
  Properties:
    QueueName: payments.fifo
    FifoQueue: true
    ContentBasedDeduplication: true
    DeduplicationScope: messageGroup
    FifoThroughputLimit: perMessageGroupId
    VisibilityTimeout: 60
    RedrivePolicy:
      deadLetterTargetArn: !GetAtt PaymentsDLQ.Arn
      maxReceiveCount: 5

Selecting standard when the requirement states “ordering” or “no duplicates” is the classic error. No amount of application logic can restore ordering that the queue never preserved, because messages from different backend hosts arrive interleaved. Choose FIFO whenever the workload demands ordering (transaction ledgers, state-machine transitions) or exactly-once semantics (payment capture, inventory decrement).

Visibility Timeout, Poison Messages, and Payload Limits

When a consumer receives a message, SQS makes it invisible to other consumers for the visibility timeout (default 30 seconds, max 12 hours). If the consumer deletes the message before the timeout expires, it is gone; if not — because the consumer crashed, or processing simply took too long — the message reappears and is delivered again. Setting the visibility timeout shorter than the actual processing time is a leading cause of duplicate processing: a Lambda taking 45 seconds against a queue with the default 30-second timeout will reprocess every message at least twice. Set the timeout to at least the p99 processing time (AWS guidance for Lambda-driven queues is at least 6× the function timeout), and for jobs of unpredictable length extend the timeout dynamically:

sqs.change_message_visibility(
    QueueUrl=queue_url,
    ReceiptHandle=handle,
    VisibilityTimeout=300  # extend by 5 minutes
)

Dead-letter queues (DLQs) capture poison-pill messages. A RedrivePolicy on the source queue specifies a maxReceiveCount (typically 3–5); once exceeded, SQS moves the message to the DLQ for offline inspection. The DLQ must match the source queue type (FIFO ↔ FIFO). Without a DLQ, malformed messages loop indefinitely, and in FIFO this is especially damaging — ordering prevents subsequent messages in the same group from being delivered until the offender is dealt with, so one bad message halts an entire group.

SQS messages are capped at 256 KB. For larger payloads — for example, a job carrying a rendered document — use the SQS Extended Client Library, which writes the payload to S3 and enqueues only a bucket/key reference. The consumer library transparently fetches on receive. Do not split payloads across multiple messages (you lose atomicity and ordering) and do not base64-encode a 2 MB blob hoping it fits.

Queue-Driven Autoscaling

For a consumer fleet on EC2 or ECS behind an SQS queue, the correct scaling signal is not CPU — it is queue backlog. CPU lags behind arrival rate and misreads a saturated consumer as “busy but coping.” The canonical scaling metric is ApproximateNumberOfMessagesVisible, but scaling directly on raw queue depth is coarse. The recommended approach is the backlog-per-instance custom metric:

backlogPerInstance = ApproximateNumberOfMessagesVisible / RunningInstances

Publish this to CloudWatch and drive a target-tracking policy on an Auto Scaling group or ECS service so each worker keeps a bounded backlog (for example, 10 messages). This yields smooth scale-out during bursts and prevents oscillation when queue depth is small but consumers are already saturated. For scale-in, pair with ApproximateAgeOfOldestMessage to avoid terminating capacity while old messages linger.

Amazon SNS: Fan-Out, Filtering, and Cross-Account Delivery

SNS is a push-based publish/subscribe service. Publishers write to a topic; SNS pushes to every subscription: SQS queues, Lambda functions, HTTP(S) endpoints, email, SMS, Kinesis Data Firehose, or mobile push. The dominant durability pattern is SNS → SQS fan-out: one topic with multiple SQS queues subscribed, so each downstream service has its own durable buffer, retry policy, and DLQ, while the publisher only knows about the topic. If a consumer service goes down for hours, its queue accumulates messages and drains on recovery — SNS alone lacks that buffering and will exhaust its retry policy.

Producer ──▶ SNS topic ──┬──▶ SQS Queue A ──▶ Service A
                         ├──▶ SQS Queue B ──▶ Service B
                         └──▶ SQS Queue C ──▶ Service C

Message filtering lets each subscription declare a JSON filter policy so SNS delivers only matching messages, avoiding the anti-pattern where every consumer receives every message and filters client-side:

{
  "eventType": ["order_placed", "order_cancelled"],
  "region": ["us-east-1", "us-west-2"]
}

Two behavioral properties matter. First, standard SNS topics do not guarantee ordering across messages — per-subscriber retry timers and independent network paths make reordering routine. If ordering matters, use an SNS FIFO topic subscribed to SQS FIFO queues; the message group ID propagates end-to-end. Otherwise, subscribers must be idempotent and tolerant of reordering. Second, HTTP(S) subscriptions retry per a delivery policy (default: three immediate retries, then exponential backoff up to one hour, then discard). Subscribers must respond 2xx within 15 seconds, validate the x-amz-sns-message-type signature, and — for unreliable endpoints — always have an SNS DLQ (redriven to SQS) so undelivered messages are captured rather than silently dropped.

Cross-account invocation is a frequent trap. When Account A publishes to a topic that fans out to a Lambda in Account B, two policies are required: the SNS topic policy (or the subscription direction) must allow the subscription, and the Lambda resource-based policy must permit lambda:InvokeFunction from sns.amazonaws.com with a SourceArn condition matching the topic. Missing the Lambda resource policy is the most common failure mode — the subscription appears healthy, but invocations are rejected with 403. If the topic is encrypted with a customer-managed KMS key, the key policy must also grant kms:Decrypt and kms:GenerateDataKey to the publishing principal and to sns.amazonaws.com.

{
  "Effect": "Allow",
  "Principal": {"Service": "sns.amazonaws.com"},
  "Action": "lambda:InvokeFunction",
  "Resource": "arn:aws:lambda:us-east-1:222222222222:function:ProcessOrder",
  "Condition": {"ArnLike": {"AWS:SourceArn": "arn:aws:sns:us-east-1:111111111111:orders"}}
}

Amazon EventBridge: Routed Event Buses

EventBridge (formerly CloudWatch Events) extends pub/sub with content-based routing, schema discovery, SaaS partner event sources, and archive/replay. Events flow through event buses (default, custom, or partner) and match against rules whose event patterns filter on JSON structure. Rules can transform payloads via input paths and input templates, attach dead-letter targets, and deliver to more than 20 native targets including Lambda, Step Functions, ECS tasks, SQS, SNS, Kinesis, and API destinations.

{
  "source": ["com.acme.orders"],
  "detail-type": ["OrderPlaced"],
  "detail": {"amount": [{"numeric": [">", 500]}]}
}

The distinction from SNS is architectural. SNS is optimized for high-throughput broadcast to homogeneous subscribers with simple attribute filtering and lower latency. EventBridge is optimized for heterogeneous event-driven architectures: many producers emit different event schemas, and consumers subscribe by pattern rather than topic. For a monolith being decomposed into microservices — especially when producers include SaaS partners or AWS services (Config, GuardDuty, CodePipeline, CloudTrail) that natively emit events — EventBridge is typically the correct fit. For extremely high-volume, low-latency fan-out to identical subscribers, SNS still wins because EventBridge has slightly higher per-event latency and a lower default throughput ceiling.

Amazon MQ: Brokered Messaging for Existing Protocols

Amazon MQ is a managed broker running ActiveMQ or RabbitMQ. It exists to migrate on-premises workloads that depend on AMQP 0-9-1, AMQP 1.0, MQTT, STOMP, OpenWire, or JMS without rewriting the application. If a payment system uses a third-party JMS broker with transactional exactly-once semantics, lifting it to Amazon MQ preserves the wire protocol and delivery guarantees while eliminating infrastructure management. Choose SQS/SNS/EventBridge for greenfield AWS-native designs; choose Amazon MQ only when protocol compatibility is the constraint.

Kinesis Data Streams

Kinesis Data Streams (KDS) is a durable, ordered, partitioned log for high-throughput streaming ingest — clickstreams, IoT telemetry, log aggregation. Records are placed into shards by PartitionKey; ordering is guaranteed within a shard, not across the stream. Each shard supports 1 MB/s or 1,000 records/s write and 2 MB/s read (or higher with Enhanced Fan-Out). Records are retained 24 hours by default, extendable to 365 days, so multiple independent consumers can replay the same history — something SQS cannot do because SQS deletes on ack.

On-demand mode removes shard math by automatically scaling up to 200 MiB/s write per stream, ideal for unpredictable traffic. Provisioned mode is cheaper at steady state where capacity is known.

Choose KDS over SQS FIFO when the workload demands ordered, replayable ingest at throughputs that FIFO cannot serve (FIFO tops out well below the millions of records/second KDS handles), when multiple independent consumers must read the same stream, or when the wording “preserve original order throughout processing” is combined with high volume.

Kinesis Data Firehose

Kinesis Data Firehose is a fully managed delivery service. It reads from a Kinesis stream or direct PUT, buffers by size (1–128 MB) or time (60–900 seconds, whichever hits first), optionally invokes a Lambda for per-record transformation (PII scrubbing, format normalization), can convert JSON to Parquet or ORC on the fly using a Glue schema, encrypts with KMS, and delivers to S3, Redshift, OpenSearch, or Splunk. It has no shards, no consumers to run, and pay-per-GB pricing.

The canonical pattern for scalable ingestion into a data lake pairs Data Streams (on-demand) as the durable buffer with Firehose for delivery to S3:

Producers → Kinesis Data Streams (on-demand) → Firehose (60s buffer, Parquet) → S3 → Athena/Glue

For ingesting millions of mobile events, encrypting them, and landing them in S3 as Parquet, the correct answer is Firehose with Parquet conversion and a KMS key — not KDS plus a custom consumer plus a hand-written Parquet writer, which is dramatically more code and infrastructure. Firehose is near-real-time and does not support consumer-side replay; when replay is required, keep KDS in the path.

Kinesis Data Analytics (now Managed Service for Apache Flink) runs SQL or Flink jobs against a stream for windowed aggregations.

Lambda Integration and Retry Semantics

Lambda integrates with these services with materially different retry behavior:

SourceBatchingOrderingOn Failure
SQS StandardUp to 10,000 msgsNoneReturns after visibility timeout; DLQ after maxReceiveCount
SQS FIFOPer groupPer groupGroup is blocked until success or DLQ
Kinesis StreamsUp to 10,000 recordsPer shardRetries block the shard until success, record expiry, or MaximumRetryAttempts/OnFailure destination
FirehoseN/A (transform)N/AFailed records land in an S3 error prefix

For SQS, keep Lambda function timeout ≤ queue visibility timeout, and set visibility timeout to at least 6× the function timeout. For Kinesis, enable BisectBatchOnFunctionError and configure an OnFailure destination (SQS or SNS) so a single poison record does not stall the entire shard indefinitely.

Selection Decision Table

RequirementCorrect choiceWhy alternatives fail
Ordered, exactly-once app messaging, minimal opsSQS FIFOStandard SQS lacks ordering/dedup; MQ adds broker management
Preserve existing AMQP/JMS/MQTT clientsAmazon MQSQS/SNS use proprietary APIs
Fan-out one event to many AWS consumers durablySNS → multiple SQSDirect producer-to-consumer coupling reintroduces the monolith; SNS-only loses messages if a consumer is down
Route heterogeneous events with filters/transformsEventBridgeSNS filter policies lack transforms, partner sources, and schema registry
Very high-throughput fan-out to identical subscribersSNSEventBridge has higher latency and lower default throughput
Ingest and replay high-volume ordered streamsKinesis Data StreamsSQS retention caps at 14 days without replay by offset
Deliver stream to S3/Redshift/OpenSearch without codeFirehoseData Streams alone requires a consumer application
Convert streaming JSON to Parquet in S3Firehose with Glue schemaCustom KDS consumer requires writing/operating a Parquet writer


← Previous: Analytics · All domains · Next: Security

Practice Application Integration questions → · Timed practice on ExamRoll.io →

Pass the whole exam — not just this question

You found this answer. Get every verified question and explanation in one place, and save hours of prep. Free to start.

Pass your exam →

Browse Amazon →

Related guides

All-in-one access

One subscription. Every exam.

Every plan unlocks unlimited answer search, practice tests, AI explanations, and the full resource library — in 20+ languages.

Monthly
24.87
Just €0.83/day
Everything included:
  • Unlimited answer search
  • Unlimited practice tests
  • AI-powered explanations
  • Full resource library
  • 20+ languages
  • Weekly content updates
  • Rewards & referrals
  • Priority support
Start free trial

No credit card required*

Best value
12 months
179.87
Just €0.49/daySave 40%
Everything included:
  • Unlimited answer search
  • Unlimited practice tests
  • AI-powered explanations
  • Full resource library
  • 20+ languages
  • Weekly content updates
  • Rewards & referrals
  • Priority support
Start free trial

No credit card required*

✓ Free plan included · ✓ Cancel anytime · ✓ All plans unlock the full product