
Amazon SQS(Simple Queue Service)是 AWS 提供的全托管消息队列服务,用于在应用程序的不同组件之间可靠地传递消息。它解决的核心问题是服务解耦——当一个组件产生的任务量超过另一个组件即时处理的能力时,消息队列充当缓冲层,让生产者和消费者以各自的速度独立运行,互不影响。
没有消息队列的系统,生产者必须等待消费者处理完当前任务才能继续,或者消费者需要持续轮询生产者是否有新任务。
两种方式都会造成资源浪费或响应延迟。SQS 将消息持久化存储,生产者投递完消息立即返回,消费者按自己的节奏取消息处理,解除两端之间的直接依赖。
SQS 的核心工作方式
SQS 的模型只有三个角色:生产者(Producer)、队列(Queue)、消费者(Consumer)。生产者向队列发送消息,消息持久存储在 SQS 中;消费者轮询队列取消息,处理完成后显式删除消息。这个”取消息 → 处理 → 删除”的三步流程是 SQS 的基础操作模式,所有的配置参数都围绕这三步展开。
SQS 没有主动推送能力,消费者必须主动向队列发送 ReceiveMessage 请求才能获取消息。这和 SNS(Simple Notification Service)的推送模式不同——SNS 将消息主动推送给订阅者,SQS 需要消费者轮询拉取。两者经常配合使用:SNS 扇出广播消息到多个 SQS 队列,每个队列后面挂接不同的消费者,实现一对多的分发架构。
标准队列与 FIFO 队列
SQS 提供两种队列类型,核心差别在于消息投递的顺序保证和吞吐量上限。
标准队列
标准队列支持近乎无限的吞吐量,每秒可以处理的 SendMessage、ReceiveMessage 和 DeleteMessage 调用次数没有实际上限。它提供”至少一次”投递保证:消息在队列中冗余存储于多个可用区,极少数情况下同一条消息可能被投递多次。消息的投递顺序是”尽最大努力”,整体上尽量维持发送顺序,但不做严格保证。
这意味着使用标准队列的消费者必须具备幂等性——同一条消息被处理两次,不应产生两次效果。以订单发货通知为例,重复处理同一条消息应该有机制检测并跳过,而不是重复发送两封邮件。
标准队列适合大多数高吞吐量场景:图片处理任务分发、电商后台订单排队、日志异步写入、批量发送通知。
FIFO 队列
FIFO(First-In-First-Out)队列提供严格的顺序保证和”精确一次”投递。发送顺序和接收顺序严格一致,同一条消息只会被投递和处理一次。代价是吞吐量受限:标准模式下每秒最多 300 次事务(每次事务最多包含 10 条消息,即每秒最多 3,000 条),开启高吞吐量模式后可以提升到每秒 3,000 次事务(即每秒最多 30,000 条消息)。
FIFO 队列的名称必须以 .fifo 结尾,一旦创建无法更改为标准队列(反之亦然),选择前应确认业务是否真正需要严格顺序。
FIFO 队列适合的场景:金融交易系统(账户借记必须在贷记之前完成)、需要严格按顺序处理命令的业务流(创建账户 → 设置权限 → 激活账户)、与第三方系统集成时对方要求按顺序接收事件。
| 对比项 | 标准队列 | FIFO 队列 |
| 吞吐量 | 近乎无限 | 300–3,000 TPS |
| 消息投递 | 至少一次,可能重复 | 精确一次 |
| 消息顺序 | 尽最大努力 | 严格保证 |
| 消费者幂等性要求 | 必须 | 不需要 |
| 适合场景 | 高吞吐量、对顺序容忍 | 严格顺序、金融事务 |
创建队列与关键配置参数
在 AWS 控制台搜索 SQS,进入后点击「创建队列」。以下几个配置项决定了队列的行为,需要在创建时根据业务需求判断。
可见性超时(Visibility Timeout)
可见性超时是 SQS 最重要的配置参数,也是最容易误解的一个。当消费者取出一条消息后,这条消息不会立即从队列中删除,而是变成”不可见”状态,持续可见性超时所设定的时长。在这段时间内,其他消费者看不到这条消息,当前消费者有足够时间处理并删除它。如果超时到期前消费者没有删除消息,消息重新变为可见,可以被其他消费者再次取走处理。
可见性超时的设置原则是:略大于消费者处理一条消息所需的最长时间。设置过短,消费者还没处理完消息就重新可见,导致重复处理;设置过长,消费者处理失败后队列长时间看不到这条消息,延迟了重试。可见性超时范围是 0 秒到 12 小时,默认 30 秒,配合 Lambda 使用时应设为 Lambda 函数超时时间的 6 倍。
用 AWS CLI 创建一个标准队列,设置 5 分钟可见性超时和 14 天消息保留期:
aws sqs create-queue \
–queue-name order-processing-queue \
–attributes ‘{
“VisibilityTimeout”: “300”,
“MessageRetentionPeriod”: “1209600”,
“ReceiveMessageWaitTimeSeconds”: “20”
}’
消息保留期(Message Retention Period)
消息在队列中保存的最长时间,范围 1 分钟到 14 天,默认 4 天。超过保留期未被消费的消息自动删除。对于关键业务消息,建议设为 14 天,给消费者故障后的充足恢复时间;对于时效性强的实时任务(如即时通知),较短的保留期可以避免队列积压过期消息。
长轮询 vs 短轮询
SQS 的消费者需要主动发起请求才能取消息。默认的短轮询(ReceiveMessageWaitTimeSeconds = 0)会立即返回响应,即使队列中暂时没有消息也会返回空响应,每次空响应同样计费。
长轮询(设置 ReceiveMessageWaitTimeSeconds 为 1–20 秒)让 SQS 在收到消息或等待时间到期后才返回响应,大幅减少空响应次数。在消息间歇性到达的场景下,长轮询可以减少约 90% 的空响应,直接降低请求次数对应的费用。生产环境中应始终启用长轮询,设置 ReceiveMessageWaitTimeSeconds = 20 是最常见的推荐配置。
发送和接收消息
用 AWS CLI 向队列发送一条消息:
# 获取队列 URL
QUEUE_URL=$(aws sqs get-queue-url \
–queue-name order-processing-queue \
–query QueueUrl –output text)
# 发送消息
aws sqs send-message \
–queue-url $QUEUE_URL \
–message-body ‘{“orderId”: “order-001”, “userId”: “user-123”, “amount”: 299.99}’ \
–message-attributes ‘{
“OrderType”: {
“DataType”: “String”,
“StringValue”: “express”
}
}’
用 Python boto3 接收并处理消息:
import boto3
import json
sqs = boto3.client(‘sqs’, region_name=’ap-east-1′)
queue_url = ‘https://sqs.ap-east-1.amazonaws.com/123456789012/order-processing-queue’
# 接收最多 10 条消息,长轮询等待最多 20 秒
response = sqs.receive_message(
QueueUrl=queue_url,
MaxNumberOfMessages=10,
WaitTimeSeconds=20,
MessageAttributeNames=[‘All’]
)
messages = response.get(‘Messages’, [])
for message in messages:
body = json.loads(message[‘Body’])
receipt_handle = message[‘ReceiptHandle’]
print(f”处理订单:{body[‘orderId’]}”)
# 处理业务逻辑
process_order(body)
# 处理成功后删除消息
sqs.delete_message(
QueueUrl=queue_url,
ReceiptHandle=receipt_handle
)
消息处理完成后必须显式调用 delete_message 删除,这是 SQS 设计的关键点。消费者不删除消息,超时后消息重新变为可见,另一个消费者实例会再次取走处理,这也是标准队列”至少一次”投递特性的实现基础。
死信队列(DLQ)配置
死信队列(Dead Letter Queue)是处理反复失败消息的机制。当一条消息在主队列中被取走超过 maxReceiveCount 次仍未被成功删除,SQS 将这条消息自动转移到指定的死信队列,不再继续重试。
死信队列的价值在于防止”毒消息”循环:一条消息因为格式错误或业务异常无法被正常处理,如果没有 DLQ,它会在可见性超时到期后不断重新出现,消耗消费者大量资源,同时阻碍后续正常消息的处理。将这类消息隔离到 DLQ,开发人员可以单独查看消息内容,分析失败原因,修复问题后再将消息从 DLQ 重新投递回主队列处理。
创建死信队列并关联到主队列:
# 先创建死信队列
aws sqs create-queue \
–queue-name order-processing-dlq \
–attributes ‘{“MessageRetentionPeriod”: “1209600”}’
# 获取 DLQ 的 ARN
DLQ_ARN=$(aws sqs get-queue-attributes \
–queue-url https://sqs.ap-east-1.amazonaws.com/123456789012/order-processing-dlq \
–attribute-names QueueArn \
–query Attributes.QueueArn –output text)
# 为主队列配置 DLQ,超过 3 次接收后转移
aws sqs set-queue-attributes \
–queue-url $QUEUE_URL \
–attributes “{
\”RedrivePolicy\”: \”{\\\”deadLetterTargetArn\\\”:\\\”$DLQ_ARN\\\”,\\\”maxReceiveCount\\\”:\\\”3\\\”}\”
}”
maxReceiveCount 的值应根据业务对重试次数的容忍度来设定,通常设为 3–5 次。死信队列必须和主队列在同一 AWS 账号和区域,且类型相同(标准队列的 DLQ 必须也是标准队列,FIFO 队列的 DLQ 必须是 FIFO 队列)。
SQS 与 Lambda 集成
SQS 和 Lambda 的组合是 AWS 异步处理架构的核心模式:Lambda 自动轮询 SQS 队列,有消息时触发函数执行,处理完成后自动删除消息,不需要维护任何轮询基础设施。关于 Lambda 函数的创建和事件触发配置,可以参考 AWS Lambda教程。
创建事件源映射
在 Lambda 控制台的触发器配置中选择 SQS,或用 CLI 创建事件源映射:
aws lambda create-event-source-mapping \
–function-name order-processor \
–event-source-arn arn:aws:sqs:ap-east-1:123456789012:order-processing-queue \
–batch-size 10 \
–maximum-batching-window-in-seconds 5 \
–function-response-types ReportBatchItemFailures
事件源映射建立后,Lambda 服务开始轮询 SQS 队列,有消息时将一批消息作为一个事件传递给 Lambda 函数。Lambda 从 5 个并发批次开始,随着队列消息积压增加,每分钟最多增加 60 个并发函数,最高达到 1,000 个并发实例。
可见性超时的黄金规则
Lambda + SQS 配置中最常见的问题是可见性超时设置不当。可见性超时必须满足以下公式:
可见性超时 ≥ Lambda 函数超时时间 × 6 + 批处理窗口时间(MaximumBatchingWindowInSeconds)
Lambda 函数超时时间如果设为 60 秒,批处理窗口 5 秒,则可见性超时至少应设为 365 秒。设置过短时,Lambda 函数还在处理中,队列就认为处理失败,将消息重新投入队列,导致另一个 Lambda 实例重复处理同一条消息。
部分批处理失败(ReportBatchItemFailures)
默认情况下,Lambda 处理一批消息时,只要有一条失败,整批消息都会重新回到队列。这意味着 10 条消息里 9 条处理成功、1 条失败,成功的 9 条也会被重复处理。
启用 ReportBatchItemFailures 后,Lambda 函数可以在响应中指明哪些消息处理失败,只有失败的消息回到队列,成功的消息正常删除。Lambda 函数需要返回对应的格式:
def lambda_handler(event, context):
failed_message_ids = []
for record in event[‘Records’]:
message_id = record[‘messageId’]
body = json.loads(record[‘body’])
try:
process_order(body)
except Exception as e:
print(f”处理消息 {message_id} 失败:{e}”)
failed_message_ids.append(message_id)
# 返回失败消息的 ID,只有这些消息会重新回队列
return {
‘batchItemFailures’: [
{‘itemIdentifier’: msg_id}
for msg_id in failed_message_ids
]
}
生产环境中应始终启用 ReportBatchItemFailures,并配合死信队列设置 maxReceiveCount,确保反复失败的消息最终被隔离到 DLQ 而不是无限重试。
IAM 权限配置
Lambda 执行角色需要具备访问 SQS 的权限才能读取和删除消息。最小权限策略应包含 sqs:ReceiveMessage、sqs:DeleteMessage 和 sqs:GetQueueAttributes。如果队列启用了 KMS 加密,还需要添加对应 KMS 密钥的 kms:Decrypt 权限。关于 IAM 角色和权限策略的配置方式,可以参考 AWS IAM 权限管理教程。
计费方式
SQS 按请求次数计费,每月前 100 万次请求永久免费。超出免费额度后,标准队列 $0.40/百万次请求,FIFO 队列 $0.50/百万次请求。同一 AWS 区域内 SQS 与 EC2、Lambda 之间的数据传输免费,数据传输到公网才收费。
几个影响实际成本的关键点:
长轮询显著降低请求成本。 消费者使用短轮询时,每次空响应也计费。一个消费者每秒发一次请求,每月产生约 260 万次请求,大部分可能是空响应。启用长轮询后,同一个消费者每月请求次数可以减少 90% 以上,在消息不密集的场景下效果尤其明显。
批量发送和接收降低单条消息的请求成本。 SendMessageBatch 支持单次发送最多 10 条消息,ReceiveMessage 支持单次接收最多 10 条消息(标准队列)或 10 条(FIFO 队列),每次批量操作计为 1 次请求。高吞吐量场景下使用批量操作可以将请求次数减少到 1/10。
超过 256KB 的消息需要使用 S3 扩展客户端。 SQS 单条消息上限为 256KB,大于这个大小的消息(如处理结果、序列化对象)应存入 S3,SQS 消息只传递 S3 对象的引用。这个模式同时减少了 SQS 请求的费用,因为实际传输的消息体变小,处理消息的 Lambda 函数也只需要从 S3 读取必要的数据。
关于 AWS 各产品账单的构成和估算方式,可以参考 亚马逊云服务器价格 的完整分析。
常见使用场景
订单异步处理
电商的典型架构是:用户下单 API 接收请求后立即将订单消息投入 SQS,返回”订单已提交”给用户;后端 Worker(EC2 或 Lambda)异步从队列取出订单,依次完成库存扣减、支付验证、物流对接等操作。用户无需等待这些耗时操作完成,前端响应时间从数秒降到毫秒级,后端各环节可以独立扩缩容。
微服务之间的解耦
多个微服务直接调用时,一个服务故障会级联导致调用方超时或失败。引入 SQS 作为中间层,上游服务投递消息后立即返回,下游服务故障期间消息在队列中积压,服务恢复后继续处理,不会丢失数据。结合 AWS DynamoDB 存储处理结果,可以构建完整的异步处理链路,各环节状态持久化且相互独立。
图片和文件异步处理
用户上传文件后,应用立即返回上传成功,同时将处理任务(生成缩略图、提取文字、格式转换)投入 SQS。Lambda 订阅队列,异步执行处理任务,结果写回 S3。这个模式将高延迟的处理任务完全从请求路径中移出,同时 Lambda 根据队列积压自动扩缩并发实例,峰值时能处理大量并发上传,空闲时缩容到零,不产生计算费用。
账号开通与代理充值
使用 SQS 需要有效的 AWS 账号,SQS 本身没有资源配额申请门槛,创建队列和开始使用不需要额外审批。对于长期运行消息处理业务、月均 SQS 请求量超过千万次的团队,通过 AWS 代理商 渠道充值可以享受代理专属折扣(低至 7 折),付款支持 USDT 和对公转账,适合没有海外信用卡或需要企业对公结算的团队,账号免实名、免绑卡,1 分钟极速交付。



