首页 时政热点 科技头条 智能AI 安全攻防 数码硬件 开发者生态 汽车 游戏 社会热点 开源推荐 医疗健康 归档 标签 关于

在金融支付系统中实施混沌工程:来自企业级 ECS 部署的经验教训

摘要

当例行部署导致支付网关瘫痪时 三年前,某大型支付处理商的结算服务在对账高峰期曾中断四小时。根本原因并非硬件故障或 DDoS 攻击,而是在部署过程中进行的一项例行 ECS 任务替换——该操作与对单个 Redis 节点的隐性依赖相结合,导致授权链中出现连锁超时。这次事件使该公司支付了七位数的 SLA 违约金,并耗费了两个月的时间才重新赢回企业客户的信任。 在金融服务领域,对于大多数严肃的混沌工程项目而...

ECS payment_auth payment true Web 200 resource name authorization aws_ecs_task_definition
2026-09-15 1 阅读 约10分钟阅读 作者:Salim Adedeji
分享:
字号:
当例行部署导致支付网关瘫痪时 三年前,某大型支付处理商的结算服务在对账高峰期曾中断四小时。根本原因并非硬件故障或 DDoS 攻击,而是在部署过程中进行的一项例行 ECS 任务替换——该操作与对单个 Redis 节点的隐性依赖相结合,导致授权链中出现连锁超时。这次事件使该公司支付了七位数的 SLA 违约金,并耗费了两个月的时间才重新赢回企业客户的信任。 在金融服务领域,对于大多数严肃的混沌工程项目而言,其起点正是这一事件——不是从理论出发,而是通过事后分析揭示出,人们对系统故障模式的理解实际上是多么匮乏。 混沌工程不是什么新鲜事物。Netflix 使其广为人知,亚马逊云科技围绕它构建了故障注入模拟器(FIS),每一份云原生架构指南都会提及它。但那些为无状态 Web 应用程序编写的手册,在应用于运行在 Amazon ECS 上的支付系统时,往往会以发人深省、有时甚至是痛苦的方式失效。本文分享了团队在尝试应用这些方法时所获得的经验,以及从一开始就应采取什么不一样的做法。 为何支付系统打破了标准的混沌模式 标准的混沌实验基于一些假设,而支付系统在设计上却违反了这些假设。 实验可以干净利落地终止 在典型的 Web 服务中,你引入延迟,观察性能下降,然后回滚。而在支付系统中,实验过程中正在处理的交易可能处于以下几种状态之一:已授权但未捕获、已捕获但未结算,或已结算但未对账。终止实验并不会停止这些交易。它们会处于一种模糊状态,既需要人工干预,又可能引发合规异常。 影响范围可以预先定义 大多数混沌测试框架允许你针对一定比例的实例或任务进行测试。支付系统通常存在隐式状态耦合,这使得“10% 的任务”这一表述无法准确地反映出实际的影响范围。即使一个处理批量结算的 ECS 任务仅占服务集群的极小部分,它也可能成为数千笔交易的关键路径。 混沌实验可以在生产环境中自由运行 PCI DSS、SOC 2 以及大多数银行业监管规定都要求,任何会故意降低生产系统性能的操作都必须经过变更管理审批。未经审批流程就运行混沌实验会导致审计问题。许多团队往往在事后才发现这一问题。 这些限制并不意味着混沌工程在金融科技领域是被禁止的。相反,这表明该流程需要以不同的方式构建。 通用工具未能捕捉到的 ECS 特有的故障模式 ECS 引入了一类独特的故障,而那些专为 Kubernetes 或裸机 EC2 设计的混沌分析工具对此覆盖不足。 任务替换行为导致了隐藏的竞争条件 当 ECS 替换任务时(例如在部署过程中、健康检查失败或 Spot 实例中断时),根据你的部署配置,它会在排空旧任务之前启动新任务。“旧任务清空”与“新任务健康”之间的这段时间窗口,正是支付系统容易受到影响的环节。 如果你的授权服务在启动时向服务注册表或负载均衡器进行了注册,而且“最低健康百分比”配置中未考虑预热期,那么流量将到达一个尚未从参数存储加载配置或建立数据库连接池的任务。该任务会处理请求并返回错误,但由于健康检查端点返回 200 状态码,ECS 无法识别该任务已处于降级状态。 控制这一行为的配置位于 ECS 服务和任务定义中: resource "aws_ecs_service" "payment_auth" { name = "payment-authorization" cluster = aws_ecs_cluster.payments.id task_definition = aws_ecs_task_definition.payment_auth.arn desired_count = 6 deployment_minimum_healthy_percent = 100 deployment_maximum_percent = 200 health_check_grace_period_seconds = 120 deployment_circuit_breaker { enable = true rollback = true } } resource "aws_ecs_task_definition" "payment_auth" { family = "payment-authorization" container_definitions = jsonencode([{ name = "payment-auth" image = var.payment_auth_image essential = true stopTimeout = 120 healthCheck = { command = ["CMD-SHELL", "curl -f http://localhost:8080/health/ready || exit 1"] interval = 10 timeout = 5 retries = 3 startPeriod = 120 } }]) } 将 deployment_minimum_healthy_percent 设置为 100 可以防止 ECS 在滚动部署期间使任务数量低于目标值。将 health_check_grace_period_seconds 设置为 120 秒,可以让任务在 ECS 将其流量路由至这些任务之前,有足够的时间从参数存储中加载配置并预热数据库连接池。stopTimeout 设置为 120 秒,可以确保在任务清空过程中,正在进行的事务能够完成。这些数值并非默认值;它们是在混沌实验发现默认 30 秒的宽限期对于某项支付授权服务而言不够用后,经过调优得出的——该服务在启动时需要加载加密密钥并建立与多个下游依赖项的连接。 在这里,值得进行的混沌实验并非“终止一个任务”,而是“将启动时的配置加载延迟 15 秒,并观察负载均衡器向该任务发送的内容”。大多数团队直到发生事故暴露这一漏洞后,才进行这项实验。 服务发现的 TTL 超过任务生命周期 ECS 服务发现使用 Route 53 来注册任务。当任务停止运行时,DNS 记录的 TTL 决定了客户端会在多长时间内继续将请求路由到已失效的 IP 地址。在支付系统中,服务之间通过私有 DNS 相互调用,60 秒的 TTL 意味着任务停止后,连接故障将持续 60 秒。你的应用程序能否优雅地处理这种情况,取决于 HTTP 客户端的配置,而非 ECS。 在每秒处理 400 笔交易的系统中,我们将 Route 53 的 TTL 配置为 60 秒,并预期故障转移能在该时间窗口内完成。实际测得的故障转移时间为 93 秒。这一时间差源于两个我们未曾考虑到的缓存层:JVM 的默认 DNS 缓存(其默认 TTL 取决于 JVM 版本和安全管理器配置,通常为 30 秒,但在某些配置下可能无限期保留)以及 VPC 解析器缓存。在每秒 400 次交易 (TPS) 的情况下,这 93 秒的时间窗口导致大约 37000 个请求被发送到已失效的端点。实验结束后,我们将 TTL 缩短至 10 秒,并将 JVM 的 networkaddress.cache.ttl 改为与之匹配的配置: resource "aws_service_discovery_service" "payment_auth" { nam
这篇文章对您有帮助吗?

订阅66必读

每日精选科技资讯,直达你的邮箱