用 AWS FIS 和 SQS 做渐进式混沌实验,验证应用韧性

2026-09-10 36 预计阅读时间: 1 分钟
来源: aws.amazon.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

重试逻辑、熔断器和死信队列,不能只在代码评审或单元测试中“看起来正确”。应用真正遇到消息积压、消费者异常或下游不可用时,系统是否能降级、恢复并保留失败消息,需要通过接近真实环境的故障实验来验证。

AWS Fault Injection Service(FIS)可以注入受控故障,AWS Systems Manager Automation 则适合编排渐进式实验。两者结合 Amazon SQS 后,可以从小范围、短时长的测试开始,逐步观察重试、可见性超时、熔断和死信队列是否按设计工作。

先明确实验要验证什么

一次有效的 SQS 韧性实验,不是简单地“让队列坏掉”,而是要提前写出可观测的假设。例如:

  • 消费者处理失败时,消息会按照退避策略重试,而不是无限高速重试。
  • 连续失败达到阈值后,熔断器会阻止请求继续打向故障下游。
  • 超过 maxReceiveCount 的消息会进入死信队列,不会永久堵塞主队列。
  • 故障结束后,消费者可以恢复处理,积压会逐步下降。
  • 实验期间没有超出预设的错误率、延迟、积压量或成本边界。

SQS 本身通常不会直接暴露一个“让消费者失败”的开关。因此,实验对象可以是消费者运行所在的计算环境、消费者调用的下游服务,或者由 Systems Manager Automation 控制的实验开关。具体 FIS action、资源类型和权限要根据实际运行平台确认,示例中的 ARN、实例 ID 和参数都需要替换。

设计一个渐进式实验

建议把实验拆成几个阶段,而不是一开始就对整个生产队列施加长时间故障:

  1. 在开发或预生产环境验证实验模板、IAM 权限和回滚动作。
  2. 只选择一个消费者实例、一个任务或一小组消息处理分片。
  3. 将故障持续时间控制在几分钟,并设置 CloudWatch 告警作为停止条件。
  4. 观察主队列深度、消息最早到达时间、接收次数、消费者错误率和 DLQ 数量。
  5. 结束故障,确认消费者恢复,并验证 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 配置失效和恢复吞吐不足等问题,让真正的下游故障不再成为第一次测试。


相关推荐