太长不读版
即使每一个微服务都在测试部门的QA环境上通过了测试,当将其一个个部署到生产环境后,也必然会发生故障。
不能以通过测试部门的QA测试为目标,而应该为生产环境的韧性而设计。
当使用鱼骨根因分析法、因果回路图或者麦肯锡MECE分析法进行分析时,要小心不要用错场景,掉进复杂混沌世界的深渊。
面对复杂混沌的生产环境,应该本着“不信有好事”的原则来进行“明哲保身”式的软件设计,并在生产环境中利用混沌猴以及在办公区进行僵尸来袭模拟的混沌工程实践,来持续地主动揭示系统弱点,并加以改进,以提高系统韧性。
“阿里云挂了!”
5个月前的一个下午,正在客户现场的我,从微信群里得知了这一消息。
阿里云在那天,至少挂半小时。“我们在运维上的一个操作失误,导致一些客户访问阿里云官网控制台和使用部分产品功能出现问题,引发了大量吐槽。”
这是典型的一次黑天鹅事件,符合黑天鹅的三个特性:
- 完全出乎意外;
- 带来极端影响;
- 事后可编故事。
复杂和混沌的系统无法预测
科幻作家刘慈欣所创作的《三体》,受到了下面三体问题的启发。“对于3个任意质量、初始位置和速度的天体,只在牛顿万有引力定律的作用下运动,那么能预测这3个天体的运动情况吗?”在130多年前,研究过这个问题的德国数学家布隆斯和法国数学家庞加莱得出这样的结论:对于三体问题,不存在能用简单代数和积分表达的一般解析解;除特殊情况外,三体的运动通常不会重复。面对这个问题,庞加莱运用了他发明的相图理论,并且最终发现了混沌理论。无法找到解和不会重复,就无法预测。在三体问题中,科学家们熟悉其中每一个天体的性质,熟悉万有引力。但当3个这样的天体在一起互动时,运动的轨迹却不可预测。复杂的生产环境,尤其是微服务系统的生产环境,至少有3个各自独立通过了测试的系统,它们各自通过事先定义好的API实现通信。但当它们在一起互动时,结果同样不可预知。虽然庞加莱发现了混沌理论,但从那之后的70多年间,机械论的世界观仍然在科学界占据主导地位。机械论认为,大自然就像一台精密的机器,只要我们发现了其中的函数,就能精确预测事物的发展,就像精确预测日食、月食、潮汐那样。如果再凭借计算机运算这些函数,就能精确模拟原子弹爆炸和弹道轨迹,甚至能描述天气的演化过程。55年前的一天,美国气象学家洛伦兹正在第二次用计算机计算一段时间的气候变化。不过这一天,他没让计算机从头计算,而是特地选择从昨天计算的一个中间结果0.506开始往后计算。为了更细致地考察结果,他把这个中间结果的精度提高到0.506127,然后就让计算机使用与昨天同样的函数开始计算。因为使用的是同样的函数,即使精度提高了一点,后半段天气演化的过程也应该和昨天的结果相吻合。他一边想,一边去咖啡馆喝了杯咖啡。等他回来查看时,顿时大吃一惊:与昨天的天气演化曲线相比,刚刚引入的0.000127这么小的差异,随着函数中时间变量的推移,从重合开始逐渐分道扬镳,最终令计算出的最后结果发生了天壤之别。再次验算,他发现计算机的计算没有问题。他由此发现,刚刚引入的那个微小误差,会以非线性的方式增长,从而造成截然不同的后果。更重要的是,这种微小的误差很容易被人们所忽视,此时又怎样能找出造成不同后果的原因呢?这便产生了蝴蝶效应这个惊世说法:一只南美洲亚马逊热带雨林中的蝴蝶,偶尔扇动了几下翅膀,就可以在两周后引起美国得克萨斯州的一场龙卷风。如果把蝴蝶换成为生产环境编写软件的工程师呢?一年多前的一天,一位亚马逊S3服务团队成员正在根据运维剧本移除少量的服务器。一不小心,他输错了命令,导致多于预期的服务器被移除。此后的4个小时内,美国成千上万的网站无法正常运转。在复杂和混沌的系统中,人、事、物之间的相互作用大多都是非线性的,初始条件千差万别。三体互动无法预测,细微原因不易发现。此时,又如何能保证“不能也不该出现失误”呢?难道要——用解决“石头、剪子、布”的简单思路,来解决气象预测之类的混沌问题?
英国咨询师斯诺登用他所创造的“栖息地”框架,把世间的问题分为5种:- 明显的问题
- 繁杂的问题
- 复杂的问题
- 混沌的问题
- 紊乱的问题
专注于持续发现约束,而不是寻找根本原因
应对黑天鹅事件的策略可以有3个:- 承认无法预测黑天鹅;
- 增强个体抗打击能力;
- 设法利用试错来获利。
识别问题种类。使用“栖息地”框架来确定生产环境属于哪种问题。如果判断生产环境是复杂和混沌的问题,那么在分析问题时,就不要使用麦肯锡MECE分析法、鱼骨根因分析法和因果回路图,承认无法预测黑天鹅,转而使用下面的方法。
确定系统愿景。栩栩如生地描述系统在所期望的状态下是如何运行的。系统未来引人入胜的愿景,确定了下面行动的方向。比如:即使错误代码要禁用部分内部IP,系统仍然能保证核心产品访问链路依旧通畅。
系统成员关系。画微服务系统用例图,在图中画出微服务系统所有的核心服务、支持服务和通用服务,及其相互关系,并画出与这些服务交互的人和外部系统。
识别系统约束。参考用例图,对用户旅程进行事件风暴,并在其中识别约束、人和外部系统。在识别约束时,一方面对于与系统交互的人,要考虑“他们的感受和自尊心”,因为这些也是我们要考虑的约束;另一方面,也要考虑约束的延迟性,警惕忽视“时滞性”的不耐烦所导致的系统“振荡”,比如总也调不好水温的淋浴器。
明哲保身原则。抱着“不信有好事”的信念对每个微服务进行设计和重构,以增强个体抗打击能力。每一个微服务经过这番设计后,即使其所依赖的其他微服务都发生故障,甚至自身也发生了局部故障,也能继续运行。此时可以针对上面所识别出的约束,考虑使用超时、断路器、舱壁、快速失败、任其崩溃并替换等设计模式来增强系统韧性。同时要避免连累反应、层叠失效、阻塞的线程、自黑式攻击、叠罗汉、缓慢的响应、无限长结果集等反模式。
频繁小型“引爆”。既然不可能构建第二个阿里云去做测试,那我们可以考虑使用混沌猴工具,来在生产环境中主动关闭一些非“致命”的服务实例,以检验微服务系统是否能自动修复故障,另外更重要的是能频繁小批量地释放“能量”,以免系统达到灾难前的临界状态。此时一旦发现弱点,就立即进行改进。为了验证团队在人员发生变动的情况下依旧能正常运转,可以考虑进行“僵尸来袭模拟”,即从团队里随机选择50%的人,并告诉他们在当天会被视为僵尸,他们虽然来上班,但需要远离工作,并且对与其所进行的任何沟通尝试都不做任何反应。此时同样要识别在团队组织方面所发现的弱点,并进行改进。这样不断小规模试错,就能获得系统稳定性的最大利益。
总结
三体互动无法预测,细微原因不易发现,复杂和混沌的系统无法预测。
面对复杂混沌系统,用解决“石头、剪子、布”的简单思路,会坠入深渊。此时应该专注于持续发现约束,而不是寻找根本原因。
约束能启发我们识别临界状态,促使我们把各个微服务打造成“明哲保身”且能自愈的自治子系统,并用频繁小型的引爆避免进入临界状态,从而把整个系统打造成一个韧性系统。