Reading35 min read·Module 2High exam weight

Amazon SQS (Queues & Decoupling)

Key concepts

  • Standard vs FIFO queues

  • Visibility timeout

  • Dead letter queues

  • Long polling vs short polling

  • Message retention period

Overview

Amazon Simple Queue Service (SQS) is a fully managed message queuing service that enables you to decouple and scale microservices, distributed systems, and serverless applications. SQS eliminates the complexity of managing message-oriented middleware and allows you to send, store, and receive messages between software components at any volume.

Understanding SQS is critical for the SAA-C03 exam because it's a foundational service for building resilient, loosely coupled architectures. You must know the differences between Standard and FIFO queues, configure visibility timeouts and dead-letter queues properly, understand polling strategies, and design for decoupling and load leveling scenarios.

SQS Decoupling

SQS enables loose coupling by allowing producers to send messages without knowing who processes them and when. Messages persist in the queue until successfully processed, preventing data loss during consumer failures or traffic spikes.

Exam Tip

Exam questions frequently test Standard vs FIFO queue selection, visibility timeout configuration, DLQ setup, and scaling EC2/Lambda consumers based on queue metrics. Know when ordering matters (FIFO) vs throughput (Standard).


Key Concepts

SQS Overview

SQS Architecture Overview
Figure 1: SQS decouples producers from consumers with message persistence

Amazon SQS Basics

Amazon SQS is a pull-based messaging service where consumers poll the queue for messages. Key characteristics:

  • Fully Managed: No infrastructure to manage
  • Highly Available: Distributed across multiple AZs
  • Scalable: Handles any message volume
  • Secure: Encryption at rest and in transit
  • Cost-Effective: Pay only for what you use

Standard vs FIFO Queues

Standard vs FIFO Queues
Figure 2: Standard queues offer high throughput while FIFO guarantees ordering

Standard vs FIFO Queues

FeatureStandard QueueFIFO Queue
ThroughputNearly unlimited300 TPS (3,000 with batching)
OrderingBest-effort (may be out of order)Strict first-in-first-out
DeliveryAt-least-once (may have duplicates)Exactly-once processing
DeduplicationNone (handle in application)5-minute deduplication window
Use CaseHigh throughput, duplicate-tolerantOrder-sensitive, no duplicates
NamingAny nameMust end with .fifo
TEXTQueue Type Comparison
STANDARD QUEUE:
├── Delivery: At-least-once (duplicates possible)
├── Ordering: Best-effort (may be out of order)
├── Throughput: Nearly unlimited TPS
├── Deduplication: None built-in
└── Best For:
    ├── High-volume workloads
    ├── Duplicate-tolerant processing
    ├── Application logs
    └── Background job processing

FIFO QUEUE:
├── Delivery: Exactly-once processing
├── Ordering: Strict FIFO (within message group)
├── Throughput: 300 TPS (3,000 with batching)
├── Deduplication: 5-minute window
└── Best For:
    ├── Financial transactions
    ├── Order processing (e-commerce)
    ├── Command sequences
    └── Events requiring strict ordering

Message Groups (FIFO)

Message Groups

FIFO queues use Message Group IDs to ensure ordering within a group while allowing parallel processing across groups. Messages with the same group ID are processed in order, but different groups can be processed concurrently.

TEXTMessage Groups Example
FIFO QUEUE WITH MESSAGE GROUPS:

Message Group: "user-123"          Message Group: "user-456"
┌──────────────────────────┐       ┌──────────────────────────┐
│ Order 1 → Order 2 → 3    │       │ Order A → Order B → C    │
│ (processed in sequence)  │       │ (processed in sequence)  │
└──────────────────────────┘       └──────────────────────────┘
        │                                    │
        └──────────┬─────────────────────────┘
                   │
                   ▼
          PARALLEL PROCESSING
          (Different groups processed concurrently)

USE CASES:
├── Per-user: MessageGroupId = userId (user actions in order)
├── Per-order: MessageGroupId = orderId (order steps in order)
├── Per-device: MessageGroupId = deviceId (device events in order)
└── Single group: MessageGroupId = "all" (all messages in order)

Queue Configuration

Visibility Timeout

Visibility Timeout

The visibility timeout determines how long a message is hidden from other consumers after being received. During this time, the consumer processes and deletes the message. If not deleted, the message becomes visible again for reprocessing.

TEXTVisibility Timeout Behavior
VISIBILITY TIMEOUT FLOW:

Time 0s: Consumer A receives Message
         └── Message becomes INVISIBLE

Time 0-30s: Consumer A processing...
            └── Other consumers cannot see message

Time 30s (default timeout):
├── If deleted: Message removed permanently ✓
└── If NOT deleted: Message becomes VISIBLE again
                    └── Another consumer can receive it

CONFIGURATION:
├── Default: 30 seconds
├── Minimum: 0 seconds
├── Maximum: 12 hours
└── Can be extended programmatically (ChangeMessageVisibility)

BEST PRACTICE:
├── Set timeout > expected processing time
├── Add buffer for retries/errors
├── Extend timeout if processing takes longer
└── Rule of thumb: 6x average processing time

Visibility Timeout Scenarios

ScenarioVisibility TimeoutWhy
Quick processing (< 5s)30 seconds (default)Fast retry if failure
Image processing (2 min)5-10 minutesAllow completion + buffer
Video transcoding (30 min)1 hourLong processing needs buffer
Batch processingExtend dynamicallyUnpredictable duration

Message Retention

Message Retention

Message retention period determines how long messages stay in the queue if not processed. After this period, messages are automatically deleted regardless of whether they were processed.

TEXTMessage Retention Configuration
MESSAGE RETENTION:

├── Default: 4 days
├── Minimum: 1 minute
├── Maximum: 14 days

IMPORTANT CONSIDERATIONS:
├── Messages deleted after retention period
├── Cannot be recovered once deleted
├── DLQ retention should be longer than source queue
└── Original timestamp preserved when moved to DLQ

SCENARIO (DLQ RETENTION):
Source Queue: 4 days retention
DLQ: 14 days retention

Day 0: Message sent to source queue
Day 3: Message moved to DLQ (after 3 failed attempts)
       └── Message has 11 days left (14 - 3 = 11)
           NOT 14 days from DLQ arrival!

Delay Queues

Delay Queues

Delay queues let you postpone the delivery of new messages for a specified duration. Messages sent to delay queues remain invisible for the delay period before being available for processing.

TEXTDelay Queue Configuration
DELAY QUEUE:

├── Default: 0 seconds (no delay)
├── Maximum: 15 minutes
├── Applies to: All new messages in queue

USE CASES:
├── Rate limiting API calls
├── Scheduling delayed processing
├── Building retry mechanisms
├── Coordinating timed workflows

MESSAGE-LEVEL DELAY (Standard Queue only):
├── Override queue-level delay per message
├── Use DelaySeconds parameter when sending
├── Not supported in FIFO queues
└── Range: 0 to 15 minutes

Dead Letter Queues (DLQ)

Dead Letter Queue Architecture
Figure 3: DLQ captures messages that fail processing repeatedly

Dead Letter Queues

A Dead Letter Queue (DLQ) captures messages that cannot be processed successfully after a specified number of attempts. DLQs help isolate problematic messages for debugging without blocking the main queue.

TEXTDLQ Configuration
DEAD LETTER QUEUE SETUP:

Source Queue ──────► Consumer
     │                  │
     │              Process
     │                  │
     │         ┌───────┴───────┐
     │         │               │
     │      Success         Failure
     │         │               │
     │      Delete          Return
     │      Message        to Queue
     │                        │
     │                    Retry...
     │                        │
     │              (after maxReceiveCount)
     │                        │
     └──────────► Dead Letter Queue

REDRIVE POLICY (Source Queue):
{
  "deadLetterTargetArn": "arn:aws:sqs:region:account:my-dlq",
  "maxReceiveCount": 3
}

KEY SETTINGS:
├── maxReceiveCount: Times message received before DLQ (1-1000)
├── DLQ must be same type (Standard → Standard, FIFO → FIFO)
├── DLQ retention > Source retention (best practice)
└── Redrive allow policy: Controls which queues can use DLQ

DLQ Redrive

DLQ Redrive

DLQ redrive allows you to move messages from the DLQ back to the source queue (or another queue) for reprocessing after fixing the underlying issue.

TEXTDLQ Redrive Process
DLQ REDRIVE WORKFLOW:

1. IDENTIFY: Messages appear in DLQ
   └── Set CloudWatch alarm on ApproximateNumberOfMessagesVisible

2. INVESTIGATE: Analyze failed messages
   ├── Check message content
   ├── Review consumer logs
   └── Identify root cause

3. FIX: Resolve the underlying issue
   ├── Fix consumer code
   ├── Update dependencies
   └── Correct configuration

4. REDRIVE: Move messages back
   ├── AWS Console: Start message redrive
   ├── CLI: aws sqs start-message-move-task
   └── Messages return to source queue

REDRIVE ALLOW POLICY (on DLQ):
{
  "redrivePermission": "byQueue",
  "sourceQueueArns": [
    "arn:aws:sqs:region:account:source-queue"
  ]
}

Polling Strategies

Short Polling vs Long Polling

FeatureShort PollingLong Polling
Wait TimeReturns immediatelyWaits up to 20 seconds
Empty ResponsesMany (if queue empty)Fewer
CostHigher (more API calls)Lower
LatencyHigher (many requests)Lower (fewer requests)
ConfigurationWaitTimeSeconds = 0WaitTimeSeconds = 1-20

Long Polling

Long polling reduces costs and improves efficiency by allowing the consumer to wait for messages instead of returning immediately. The consumer waits up to 20 seconds for a message before returning empty.

TEXTPolling Configuration
SHORT POLLING (Default):
├── ReceiveMessageWaitTimeSeconds = 0
├── Returns immediately (even if empty)
├── Queries subset of SQS servers
├── May return empty even when messages exist
└── Higher cost (more API calls)

LONG POLLING (Recommended):
├── ReceiveMessageWaitTimeSeconds = 1-20
├── Waits for messages to arrive
├── Queries ALL SQS servers
├── Reduces empty responses
└── Lower cost, better efficiency

CONFIGURATION OPTIONS:
1. Queue-level: Set ReceiveMessageWaitTimeSeconds
2. Request-level: Use WaitTimeSeconds parameter

BEST PRACTICE:
├── Use long polling (20 seconds recommended)
├── Set at queue level for consistency
├── Reduces costs significantly
└── Note: Single-threaded apps polling multiple queues
    may need short polling

Lambda Integration

SQS with Lambda

Lambda can be configured as an event source for SQS, automatically polling the queue and invoking your function when messages arrive. Lambda manages scaling, batching, and error handling.

TEXTLambda Event Source Mapping
LAMBDA + SQS INTEGRATION:

                    Event Source Mapping
SQS Queue ─────────────────────────────────► Lambda Function
              │                                    │
              │  Polls queue                       │
              │  Batches messages                  │
              │  Invokes function                  │
              │  Manages scaling                   │
              └────────────────────────────────────┘

SCALING BEHAVIOR (Standard Queue):
├── Starts with 5 concurrent batches
├── Scales up to 300 more per minute
├── Maximum: 1,250 concurrent invocations
├── Scales down when traffic decreases
└── Minimum: 2 concurrent invocations

CONFIGURATION OPTIONS:
├── Batch Size: 1-10,000 messages (default: 10)
├── Batch Window: 0-300 seconds (wait for full batch)
├── Maximum Concurrency: Limit concurrent invocations
├── Report Batch Item Failures: Return partial failures
└── Function Error Handling: DLQ on function level

FIFO QUEUE WITH LAMBDA:
├── Maintains message order within group
├── One concurrent invocation per message group
├── Multiple groups = parallel processing
└── Scales based on number of message groups

Batch Processing

JSONLambda Batch Configuration
{
  "EventSourceArn": "arn:aws:sqs:region:account:my-queue",
  "FunctionName": "my-function",
  "BatchSize": 100,
  "MaximumBatchingWindowInSeconds": 30,
  "ScalingConfig": {
    "MaximumConcurrency": 50
  },
  "FunctionResponseTypes": ["ReportBatchItemFailures"]
}
TEXTPartial Batch Failure Handling
BATCH ITEM FAILURE REPORTING:

Scenario: Batch of 10 messages, 2 fail

WITHOUT ReportBatchItemFailures:
├── Entire batch retried
├── 8 successful messages reprocessed
├── Duplicates in downstream systems
└── Inefficient, wastes compute

WITH ReportBatchItemFailures:
├── Return failed message IDs
├── Only failed messages retried
├── Successful messages deleted
└── Efficient, no duplicates

LAMBDA RESPONSE FORMAT:
{
  "batchItemFailures": [
    { "itemIdentifier": "message-id-1" },
    { "itemIdentifier": "message-id-2" }
  ]
}

Auto Scaling with SQS

EC2 Auto Scaling with SQS

EC2 Auto Scaling groups can scale based on SQS queue depth using the ApproximateNumberOfMessages metric. This enables dynamic scaling to handle varying workloads efficiently.

TEXTAuto Scaling Based on Queue Depth
AUTO SCALING ARCHITECTURE:

SQS Queue ──► CloudWatch Metric ──► Auto Scaling Policy ──► EC2 Instances
                    │
     ApproximateNumberOfMessagesVisible
                    │
                    ▼
         Target: Messages per instance

SCALING METRICS:
├── ApproximateNumberOfMessagesVisible: Messages available
├── ApproximateNumberOfMessagesNotVisible: In-flight messages
├── ApproximateAgeOfOldestMessage: Queue backlog age
└── NumberOfMessagesReceived: Incoming rate

CUSTOM METRIC FORMULA:
Backlog per Instance = ApproximateNumberOfMessagesVisible
                       ─────────────────────────────────────
                       Running Capacity (instances)

Target Value = Acceptable backlog per instance

SCALING POLICY EXAMPLE:
├── Metric: ApproximateNumberOfMessagesVisible
├── Target: 100 messages per instance
├── Scale Out: When > 100 messages/instance
├── Scale In: When < 50 messages/instance
└── Cooldown: 300 seconds

Security

Encryption

TEXTSQS Encryption Options
ENCRYPTION AT REST:
├── SSE-SQS: AWS managed key (default, no cost)
├── SSE-KMS: Customer managed KMS key
│   ├── More control over key rotation
│   ├── Audit via CloudTrail
│   └── Cross-account access possible
└── Enable at queue creation or modify later

ENCRYPTION IN TRANSIT:
├── HTTPS endpoints enforced
├── TLS 1.2+ required
└── VPC endpoints available (PrivateLink)

ACCESS POLICY EXAMPLE (KMS):
{
  "Effect": "Allow",
  "Principal": {"AWS": "arn:aws:iam::account:role/consumer"},
  "Action": [
    "kms:Decrypt",
    "kms:GenerateDataKey"
  ],
  "Resource": "*"
}

Access Control

JSONSQS Access Policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "sns.amazonaws.com"
      },
      "Action": "sqs:SendMessage",
      "Resource": "arn:aws:sqs:region:account:my-queue",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:sns:region:account:my-topic"
        }
      }
    }
  ]
}

Best Practices

  1. Use Long Polling: Set ReceiveMessageWaitTimeSeconds to 20 seconds to reduce costs
  2. Configure DLQs: Always set up dead-letter queues for production workloads
  3. Design Idempotent Consumers: Handle duplicate messages gracefully (Standard queues)
  4. Set Appropriate Visibility Timeout: Match to processing time plus buffer
  5. Use Message Groups Wisely: Maximize parallelism in FIFO queues
  6. Monitor Queue Metrics: Set alarms on queue depth, DLQ count, and message age
  7. Use Batch Operations: Reduce API calls with batch send/receive/delete
  8. Consider FIFO Only When Needed: Standard queues offer higher throughput

Common Exam Scenarios

Exam Scenarios

ScenarioSolutionWhy
Decouple web tier from processingSQS Standard between tiersBuffering, independent scaling
Process orders in sequenceSQS FIFO queueStrict ordering required
Handle processing failuresConfigure DLQIsolate failed messages
Reduce polling costsEnable long polling (20s)Fewer API calls
Scale workers to demandAuto Scaling on queue depthDynamic capacity
Prevent duplicate processingFIFO queue or idempotent designExactly-once or handle duplicates
Messages stuck in queueIncrease visibility timeoutProcessing takes longer than timeout
Lambda batch partial failureReportBatchItemFailuresRetry only failed messages

Common Pitfalls

Pitfall 1: Visibility Timeout Too Short

Mistake: Setting visibility timeout shorter than processing time.

Why it fails: Messages reappear before processing completes; processed multiple times.

Correct Approach: Set timeout to at least 6x average processing time; extend programmatically if needed.

Pitfall 2: No Dead Letter Queue

Mistake: Not configuring a DLQ for production queues.

Why it fails: Poison messages block queue forever; no visibility into failures.

Correct Approach: Always configure DLQ; set alarms on DLQ message count.

Pitfall 3: Using FIFO When Not Needed

Mistake: Choosing FIFO queue when ordering isn't required.

Why it fails: FIFO has 300 TPS limit vs unlimited for Standard; unnecessary constraint.

Correct Approach: Use Standard unless ordering is required; design idempotent consumers.

Pitfall 4: Short Polling in Production

Mistake: Using default short polling (WaitTimeSeconds = 0).

Why it fails: Many empty responses; higher costs; unnecessary API calls.

Correct Approach: Enable long polling (20 seconds) at queue level.

Pitfall 5: DLQ Retention Shorter Than Source

Mistake: Setting DLQ retention period shorter than source queue.

Why it fails: Messages may be deleted from DLQ before you can investigate.

Correct Approach: DLQ retention should be longer (e.g., source: 4 days, DLQ: 14 days).



Quick Reference

SQS Limits

SQS Limits

ParameterStandardFIFO
ThroughputUnlimited300 TPS (3K batched)
Message Size256 KB256 KB
Retention1 min - 14 days1 min - 14 days
Visibility Timeout0s - 12 hours0s - 12 hours
Delay0 - 15 minutes0 - 15 minutes
Long Poll Wait0 - 20 seconds0 - 20 seconds
Batch Size1 - 101 - 10
In-Flight Messages120,00020,000

Message Attributes

JSONSQS Message Structure
{
  "MessageBody": "Your message content here",
  "MessageAttributes": {
    "OrderType": {
      "DataType": "String",
      "StringValue": "Premium"
    },
    "Priority": {
      "DataType": "Number",
      "StringValue": "1"
    }
  },
  "MessageDeduplicationId": "unique-id-123",
  "MessageGroupId": "order-group-456"
}

Test Your Knowledge

Q

A company processes financial transactions that must be handled in the exact order received. They expect 200 transactions per second. Which SQS queue type should they use?

AStandard queue with message ordering attribute
BFIFO queue with message groups
CStandard queue with Lambda processing
DFIFO queue - but it cannot handle this volume
Q

An application processes messages from SQS, but some messages keep reappearing after being processed. What is the most likely cause?

AThe queue retention period is too long
BLong polling is not enabled
CThe visibility timeout is shorter than processing time
DThe dead letter queue is not configured
Q

A Lambda function processes batches of 100 messages from SQS. Occasionally, 2-3 messages in a batch fail while the rest succeed. How should the function handle this efficiently?

AReturn an error to retry the entire batch
BDelete successful messages and return error
CEnable ReportBatchItemFailures and return failed IDs
DProcess messages one at a time
Q

A company wants to reduce SQS costs. Currently, consumers poll the queue every second and often receive empty responses. What should they implement?

AIncrease the number of consumers
BEnable long polling with 20-second wait time
CReduce the batch size
DSwitch to FIFO queue

Further Reading

Related services

SQSLambdaEC2