SQS doesn’t actually store your messages; it’s a sophisticated distributed ledger that tracks message state and ownership.
Let’s watch SQS in action. Imagine a web application that needs to process user sign-ups asynchronously. Instead of handling the sign-up logic directly in the web request, which would slow down the user experience, we’ll push a message to an SQS queue.
Here’s a simplified look at the process:
-
Producer (Web App): When a user signs up, the web app sends a message to an SQS queue. This message contains the user’s details.
aws sqs send-message --queue-url https://sqs.us-east-1.amazonaws.com/123456789012/user-signups --message-body '{"userId": "user123", "email": "user@example.com"}'The
send-messagecommand returns aMessageId. This ID is SQS’s internal reference to the message’s entry in its ledger. -
SQS: SQS receives the message. It doesn’t put the message "in" a physical location you can access. Instead, it records the message’s existence and assigns it a receipt handle if it were to be received later. Critically, SQS uses a distributed hash table (DHT) internally to ensure high availability and low latency for message operations. Each message, or rather, its metadata, is sharded across many nodes.
-
Consumer (Worker Service): A separate service, running on EC2 instances or Lambda functions, polls the SQS queue for messages.
aws sqs receive-message --queue-url https://sqs.us-east-1.amazonaws.com/123456789012/user-signups --max-number-of-messages 10 --visibility-timeout 30When a message is received, SQS marks it as "in flight" for the specified
visibility-timeout. During this period, no other consumer can see or receive that same message. Thereceive-messagecommand returns the message body and aReceiptHandle. -
Processing: The consumer processes the user sign-up logic (e.g., creating a user record in a database, sending a welcome email).
-
Deletion: Once processing is successful, the consumer deletes the message from the queue.
aws sqs delete-message --queue-url https://sqs.us-east-1.amazonaws.com/123456789012/user-signups --receipt-handle "AQEBzX..."The
delete-messagecommand uses theReceiptHandleobtained during thereceive-messagecall. This tells SQS which specific instance of the message (identified by its receipt) should be removed from the active set. If the consumer fails to delete the message within the visibility timeout, SQS makes it visible again for another consumer to pick up.
This architecture decouples producers from consumers, allowing them to scale independently and handling bursts of traffic gracefully. The key to millions of messages per second lies in SQS’s internal sharding and its ability to serve send-message, receive-message, and delete-message requests with extremely low latency across a massive distributed system.
To scale to millions of messages per second, you’re not just increasing the number of consumers; you’re also dealing with the underlying SQS service’s capacity. SQS partitions queues internally to handle high throughput. When you send a message, it’s routed to a specific partition. Similarly, when you poll, you’re hitting a partition. The "millions per second" figure is an aggregate across all partitions supporting your account and region.
A common misconception is that SQS queues have a fixed throughput. In reality, SQS scales automatically. When you hit a bottleneck, it’s rarely the queue itself but more often your producer’s ability to send or your consumer’s ability to process and delete messages quickly enough. For extremely high throughput, especially with standard queues, you need to ensure your consumers are deleting messages very rapidly. If a consumer takes longer than the visibility timeout to process and delete a message, SQS will re-deliver it, leading to duplicate processing if not handled idempotently.
The most surprising true thing about SQS scaling is that SQS partitions your queue dynamically based on traffic. It’s not a static configuration you set. When you send messages, SQS determines which partition to place them in. When you poll, you’re asking for messages from any available partition that has them. This dynamic sharding is what allows SQS to absorb massive, unpredictable spikes in traffic without manual intervention. You don’t "create" partitions; SQS manages them behind the scenes.
The next concept you’ll grapple with is exactly how to ensure your consumers are deleting messages fast enough to avoid re-deliveries, especially when processing complex or long-running tasks.