
2016年,Netflix的推荐算法团队准备上线一个新模型。测试环境跑了三周,一切正常。上线前,他们按惯例跑了一次“混沌实验”——主动切断了一个推荐服务依赖的数据库连接。
结果出人意料:整个推荐系统在30秒内雪崩,首页加载失败,用户看到的是空白页面。
问题出在哪?代码里有重试机制,但没设退避。数据库一断,所有请求同时重试,瞬间把另一个服务也打爆了。重试再重试,最后谁也别想活。
如果这个bug在生产环境被用户触发,后果是什么?Netflix不敢想。但他们不用想,因为他们已经“主动崩溃”过了,在可控的环境里,在用户察觉之前。
这就是混沌工程:主动注入故障,在系统最薄弱的地方提前引爆,而不是等用户帮你引爆。
01 混沌工程不是什么
在聊怎么做之前,先澄清几个误会。
混沌工程不是随机搞破坏。 有些人一听“主动注入故障”,就觉得是没事找事,在系统里乱搞。不是的。混沌工程是“有预谋的实验”,每一步都经过设计:假设什么、注入什么、观察什么、验证什么。不是扔炸弹,是拆炸弹。
混沌工程不是只在测试环境玩。 预发环境当然可以跑,但真正的信心来自生产环境。因为生产环境的流量、数据、依赖,是任何测试环境都模拟不了的。当然,在生产环境做实验要做好防护——最小爆炸半径、实时监控、自动熔断。
混沌工程不是证明系统会崩,而是证明系统不会崩。 目标不是破坏,是验证。验证你的高可用架构是不是真的高可用,验证你的容灾机制是不是真的能容灾,验证你的监控告警是不是真的会响。
02 疫苗的原理
混沌工程的核心逻辑,和疫苗一模一样。
疫苗往你身体里注射少量灭活病毒,激发免疫系统产生抗体。真病毒来了,身体认识它,能干掉它。
混沌工程往系统里注入少量可控故障,激发系统触发熔断、限流、降级、重试。真故障来了,系统认识它,能扛住它。
没有经过混沌工程的系统,就像没打过疫苗的人,第一次遇到病毒往往扛不住。因为那些熔断限流代码可能从来没跑过,那些降级逻辑可能从来没触发过,那些备份节点可能从来没切换过。
反常识观点:系统最脆弱的时候,不是流量最大的时候,而是刚上线的时候。 因为所有保护机制都是“理论上”有效,从未被真实验证过。
03 怎么设计一个混沌实验
混沌实验不是随手敲个命令,需要完整的设计流程。
第一步:定义稳态
你要知道系统“正常”的时候是什么样子。指标是多少?延迟、错误率、吞吐量,记下来。这是实验的对照组。
第二步:提出假设
“如果我们杀了订单服务的一个Pod,用户仍然能下单。”这是一个可验证的假设。把它写下来。
第三步:注入故障
选一个故障类型,在一个小范围内触发。常见的故障类型:
基础设施:CPU飙高、内存耗尽、磁盘写满
网络:延迟、丢包、乱序、拒绝连接
应用:抛出异常、响应超时、进程崩溃
依赖:数据库连接断开、下游服务宕机
第四步:观察对比
注入后,观察系统行为。稳态指标变了没有?用户体验受影响没有?自动恢复机制触发了没有?
第五步:改进系统
如果系统扛住了,恭喜,你的假设成立。如果没扛住,你发现了一个盲点。修复它,然后换个故障类型再试。
04 从哪开始:最小爆炸半径
很多人一听混沌工程就害怕:“在生产环境搞破坏,老板会杀了我的。”
理解。所以从小开始。
第一步:选一个非核心服务。 内部工具、边缘服务,就算崩了也没人知道。先在这里练手,跑通流程。
第二步:选一个“无害”的故障类型。 比如加50ms网络延迟,不会让服务挂掉,但能让系统触发超时重试逻辑。看你的监控是不是真的会告警。
第三步:手动跑,不要自动化。 刚开始就上自动化,风险太高。手动跑几次,摸清楚系统的脾气,再把实验写成代码。
第四步:逐步扩大范围。 从边缘服务到核心服务,从低峰期到高峰期,从单一故障到复合故障。每一步都要有回滚计划。
最小爆炸半径原则: 一次实验影响的用户数控制在1%以内。出了事,最多1%的用户受影响,你能承受。
05 工具选型
混沌工程工具已经不少了,按需选择。
开源方案:
Chaos Mesh:云原生,Kubernetes环境下好用,支持Pod级别故障注入
ChaosBlade:阿里开源,支持多环境(主机、容器、K8s),故障类型丰富
Litmus:专门为K8s设计的混沌工程工具,社区活跃
商业方案:
Gremlin:混沌工程鼻祖,界面友好,安全机制完善,有免费额度
AWS FIS:Amazon的故障注入服务,和AWS生态集成好
Azure Chaos Studio:微软家的,预览阶段,但潜力不错
初创公司可以先从Chaos Mesh或ChaosBlade开始,开源免费,文档齐全。等团队成熟了,再考虑商业产品。
06 一个真实案例
去年双11前,帮一个电商客户做混沌演练。他们的核心系统是高可用架构:多可用区部署、数据库主从、缓存集群。理论上,挂了任何一个节点都不会影响用户。
我们设计了一个实验:在高峰期前两小时,杀掉一个缓存节点。
结果出乎意料:缓存集群触发rebalance,大量请求穿透到数据库。数据库扛不住,开始慢查询。慢查询又导致连接池爆满。整个链路雪崩。
问题出在哪?缓存客户端配置了“节点变更时重建连接池”的参数,重建过程中所有请求都穿透。他们之前只在单节点测试过,没试过节点被强制下线。
幸好是演练,不是真正的故障。他们有四个小时修复问题:改客户端配置、加数据库连接池上限、调降级策略。双十一当天,这个隐患没再出现。
后来他们的CTO说了一句:“以前觉得高可用架构搭好了就放心了,现在才明白,高可用不是搭出来的,是练出来的。”
07 什么时候开始混沌工程
有人问:“我们系统还在初创阶段,需要做混沌工程吗?”
我的回答是:你什么时候开始做容灾,就可以开始做混沌工程。
容灾不是买保险,买了就安心。容灾是需要验证的。你做了主从切换,得试试真切换会不会丢数据。你做了多可用区部署,得试试真切流量会不会断连。你做了限流降级,得试试真触发会不会误伤。
这些验证,就是混沌工程。
不需要等系统成熟了再做,越早做,越早发现盲点。那些盲点在系统还小的时候修复成本低,等大了再改,伤筋动骨。
写在最后
2011年,Netflix开始做混沌工程的时候,很多人都觉得他们疯了:哪有在自己系统里搞破坏的?
现在,混沌工程已经是高可用架构的标配。AWS、Google、Microsoft、阿里巴巴,都在用。不是因为他们不怕出事,是因为他们知道:与其等用户帮我们发现弱点,不如自己先找出来。
你的系统打过“疫苗”吗?那些熔断限流降级的代码,真的跑过吗?备份节点真的能切换吗?监控告警真的会响吗?
如果这些问题你答不上来,今晚回去跑一个最小的实验:关掉一台非核心服务的实例,看看会发生什么。