重试逻辑、熔断器和死信队列,不能只在代码评审或单元测试中“看起来正确”。应用真正遇到消息积压、消费者异常或下游不可用时,系统是否能降级、恢复并保留失败消息,需要通过接近真实环境的故障实验来验证。
AWS Fault Injection Service(FIS)可以注入受控故障,AWS Systems Manager Automation 则适合编排渐进式实验。两者结合 Amazon SQS 后,可以从小范围、短时长的测试开始,逐步观察重试、可见性超时、熔断和死信队列是否按设计工作。
先明确实验要验证什么
一次有效的 SQS 韧性实验,不是简单地“让队列坏掉”,而是要提前写出可观测的假设。例如:
- 消费者处理失败时,消息会按照退避策略重试,而不是无限高速重试。
- 连续失败达到阈值后,熔断器会阻止请求继续打向故障下游。
- 超过
maxReceiveCount的消息会进入死信队列,不会永久堵塞主队列。 - 故障结束后,消费者可以恢复处理,积压会逐步下降。
- 实验期间没有超出预设的错误率、延迟、积压量或成本边界。
SQS 本身通常不会直接暴露一个“让消费者失败”的开关。因此,实验对象可以是消费者运行所在的计算环境、消费者调用的下游服务,或者由 Systems Manager Automation 控制的实验开关。具体 FIS action、资源类型和权限要根据实际运行平台确认,示例中的 ARN、实例 ID 和参数都需要替换。
设计一个渐进式实验
建议把实验拆成几个阶段,而不是一开始就对整个生产队列施加长时间故障:
- 在开发或预生产环境验证实验模板、IAM 权限和回滚动作。
- 只选择一个消费者实例、一个任务或一小组消息处理分片。
- 将故障持续时间控制在几分钟,并设置 CloudWatch 告警作为停止条件。
- 观察主队列深度、消息最早到达时间、接收次数、消费者错误率和 DLQ 数量。
- 结束故障,确认消费者恢复,并验证 DLQ 消息能够被安全重放或人工处理。
SQS 的关键配置决定了实验结果。VisibilityTimeout 过短,可能导致同一条消息被多个消费者重复处理;maxReceiveCount 过高,故障消息会在主队列中重试很久;过低则可能把短暂网络抖动误判为永久失败。实验前应记录这些值,并明确业务是否具备幂等性。
一个典型的队列配置可以这样表达。以下 CloudFormation 片段可作为改造起点,实际部署前请补充加密、访问策略和环境命名规范:
Resources:
OrdersDlq:
Type: AWS::SQS::Queue
Properties:
QueueName: orders-dlq
MessageRetentionPeriod: 1209600
OrdersQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: orders
VisibilityTimeout: 60
RedrivePolicy:
deadLetterTargetArn: !GetAtt OrdersDlq.Arn
maxReceiveCount: 5
这里的含义是:消息最多被接收五次,仍然无法成功处理时进入 DLQ。这个阈值不是通用最佳实践,应结合消费者处理时长、瞬时故障持续时间和业务重试成本调整。
用 AWS CLI 启动受控实验
下面是一个可改造的 AWS FIS 实验模板骨架。它展示了实验应具备的几个部分:实验角色、停止条件、目标资源、故障动作和持续时间。由于可用的 FIS action 会随 AWS 服务和运行平台变化,actions 部分需要替换为当前环境支持的动作;不要直接把占位值部署到生产环境。
cat > fis-sqs-experiment.json <<'JSON'
{
"description": "短时测试订单消费者的失败处理能力",
"targets": {
"consumer": {
"resourceType": "aws:ec2:instance",
"resourceArns": ["arn:aws:ec2:us-east-1:123456789012:instance/i-0123456789abcdef0"],
"selectionMode": "COUNT(1)"
}
},
"actions": {
"inject-failure": {
"actionId": "REPLACE_WITH_SUPPORTED_ACTION",
"parameters": {
"duration": "PT3M"
},
"targets": {
"Instances": "consumer"
}
}
},
"stopConditions": [
{
"source": "aws:cloudwatch:alarm",
"value": "arn:aws:cloudwatch:us-east-1:123456789012:alarm:sqs-consumer-critical"
}
],
"roleArn": "arn:aws:iam::123456789012:role/FISExperimentRole"
}
JSON
EXPERIMENT_ID=$(aws fis create-experiment-template \
--cli-input-json file://fis-sqs-experiment.json \
--query 'experimentTemplate.id' \
--output text)
aws fis start-experiment --experiment-template-id "$EXPERIMENT_ID"
如果故障动作需要通过 Systems Manager Automation 执行,可以把自动化文档作为实验编排的一部分,例如切换测试开关、修改消费者实例的网络访问或暂停一个受控 worker。自动化文档必须包含清晰的恢复步骤,并限制可操作的资源范围。实验结束后,恢复动作应能独立执行,不能依赖已经处于故障状态的组件。
观测结果,而不是只看实验是否成功
实验控制台显示“Completed”并不代表应用通过了测试。需要把技术指标和业务结果放在一起判断:
ApproximateNumberOfMessagesVisible:主队列中等待处理的消息数。ApproximateNumberOfMessagesNotVisible:正在处理或处于可见性超时期间的消息数。ApproximateAgeOfOldestMessage:积压是否已经影响服务等级目标。- 消费者处理失败率、重试次数和下游请求延迟。
- DLQ 消息数量、消息接收次数和最终处理结果。
实验记录至少应包含故障开始时间、停止时间、目标资源、告警触发情况、队列峰值和恢复时间。尤其要区分“消费者恢复”与“积压清空”:前者只说明进程重新工作,后者才说明系统有足够吞吐量追上生产速度。
采用前的检查清单
- 为主队列配置 DLQ,并确认 DLQ 保留期足够长。
- 验证消息处理幂等性,避免重试导致重复扣款、重复发货等副作用。
- 为 FIS 和 Systems Manager Automation 使用最小权限 IAM 角色。
- 为队列积压、消息年龄、消费者错误率和 DLQ 设置 CloudWatch 告警。
- 先做单实例、短时长实验,再逐步扩大范围。
- 明确停止条件、人工终止命令和自动恢复路径。
- 实验后验证消息重放、告警恢复和业务数据一致性。
混沌实验的价值不在于制造一次故障,而在于把系统的恢复能力变成可重复验证的工程事实。对 SQS 消费链路而言,渐进式实验能较早暴露重试风暴、错误熔断、DLQ 配置失效和恢复吞吐不足等问题,让真正的下游故障不再成为第一次测试。