查看原文
其他

稳定性全系列(三)——放火&降级演练

易振强 极客人生THE GEEKS 2022-09-09
小编推荐:稳定性全系列,作者结合自身多年稳定性工作经验,带你快速了解线上放火&降级演练方案的制定和落地。

1.
背景
系统稳定性建设一直是研发、测试、运维团队绕不开的话题,这么多年来,我们为降低系统复杂度、提升系统可维护性绞尽脑汁,微服务架构本质是从架构层面来分而治之、化繁为简来解决系统复杂度问题,就像我们现在遇到的,微服务架构可能解决了研发问题,但并不是没有“副作用”,它增加性能、服务治理、运维等开销,同样,也给系统稳定性建设带来不少挑战。

随着业务的迭代,系统复杂度也在逐步变化,哪怕是资深架构师,一时也无法说清楚整个系统架构,稳定性工作如履薄冰,之前我们在做的一些诸如监控告警建设、线上全链路压测、弹性云扩容演练等工作,都是被动的为未来可能的风险做准备,我们没有标尺来衡量我们稳定性工作做得好不好,能打多少分,长期以来,参与这些工作的同学容易“疲惫”。这些未来的风险犹如未定期的大考,让我们“既期待又惶恐”

2.
混沌工程

于是我们在想,能不能提前“放火”——人为制造故障?就好比人类在为了抵御病毒的攻击,制造了疫苗,而疫苗的本质其实就是被虚弱的病毒,我们为什么不能在系统中注入一些弱化的故障,来看系统的反应,以方便我们更有针对性的去做措施?

Netflix把自己在云上的实践提炼出来,写了《混沌工程(Chaos Enginnering)》一书,相信里面的一些体系化的思路对大伙会很有启发。所谓混沌工程,其实一种应用经验探索来学习系统行为的方法,按照Netflix的说法,混沌工程是一门学科。

那么它与“故障测试”有什么区别吗?书中也做了简单解释,混沌工程和故障测试在关注点有一定的重合度,后者只是测试的一种方法,而前者是为了生成“新信息”的一种实践,这里的“新信息”我理解是关于系统在某些事件发生后所产生的行为的相关信息(而不是像故障测试一样只关心是否产生了对的结果),而这种信息很有可能是我们都难以预料的,混沌工程的本质目的是我们不断去调整系统,使系统更具弹性,这样一来一旦紧急事件发生,系统的行为会变得更加可预测,这也意味着对业务和用户的影响更加可控。

3.
放火&降级演练

3.1 变被动为主动

就像前面提到的,之前我们大多数稳定性工作都是被动的为未来的发生的紧急事件做准备,我们认为放火演练将改变这一局势,我们能人为提前注入故障,来看看我们系统的反应是否符合我们预期。如果系统的反应没有达到预期,故障带来的影响面也比我们预估的要大,那我们就应该好好分析到底问题出在哪里,该如何去修复。就应该是这样,只有我们清晰的看到系统的稳定性问题,才能更有动力去解决该问题。有了放火演练,我们能将更多的“假想敌”活生生构造出来。

关于放火演练,还有一点非常重要,那就是降级预案(更通俗的说就是紧急预案),降级预案按照生效方式,分为自动预案手动预案两种,当然,预案的建设得依靠工具,在自动实施的预案中,只要我们定好策略,降级工具(例如 https://github.com/didi/sds)会在系统达到某种预先设定的条件下自动处理,而在手动预案的实施过程中,我们可能需要进行业务开关、系统开关、服务降级、切流等操作,较成熟的预案会将这些操作收口,可能只需要点一次按钮就能完成整个预案的实施。理想的情况应该是,线上80%的预案是自动预案。

所以我们得出如下大致步骤:

我们常常把放火和预案结合在一起来演练,一方面我们要检测在紧急事件发生时,系统是否有超出我们预期的行为,另一方面我们也需要不断找机会来验证我们预案的有效性。介于此,我们也希望放火&降级演练能成为工程师了解自己系统行为的一个桥梁,来驱动和帮助工程师构建更具“弹性”的系统。

3.2 前提条件

我们前面已经提到了“放火”和“混沌工程”的概念,在滴滴内部,已经有定期的“盲测”演练,其实也属于放火的范畴,但“盲测”的主要目标是使因机房问题导致的故障能在X分钟内发现和资损,例如我们会定期随机停掉一台交换机,看下网络设施是否做了足够的容错。看似简单明了的举措,实际上前期已经做了充分的准备,需要记住的是,并不是任何系统都能做放火&降级演练,必须要具备如下条件才行:

能使用线上环境:如果最终不能在线上或类线上的环境进行放火,那么放火发现的行为和得出结论将没有实际的价值,所以请务必能申请到在线上环境实施。

完善的监控与告警机制:如果我们连线上系统的基本指标和行为都不清楚的话,何来预期的结果?这需要监控系统帮我们完成。另一方面,我们总不能一直盯着监控大盘来看指标,需要报警系统来保障我们能及时发现系统异常。

可预估的燃烧半径:在放火体系中,我们把它对系统的影响面形象的称之为燃烧半径,放火的首要前提一定是对业务和系统的影响控制在预期范围之内(例如XXX放火后发单接口的avg耗时涨幅不超过20%、发单量波动小于2%),前期的放火当然难以较准确的评估燃烧半径,所以我们要先“放小火”,后面再逐渐加大马力。

有对应的降级预案:在具体实施时,我们要对放火的内容进行归类和沉淀,每种放火我们要提前想好对应的降级预案是什么以及预案的触发条件。初步的降级预案是放火的前提条件,而放火最终也会促进降级预案的不断完善和进化,这是一个良性循环。

3.3 方案实施

首先我们必须承认一个事实,哪怕是经验再丰富的工程师,也无法穷举未来可能发生的紧急事件,更不要说这些紧急事件的组合了。想要真正开始放火其实并不容易,目前我们是按照如下步骤展开:

选择一个放火事件

其实最先做的应该是放火事件的归类,由于我们更关注服务端的系统稳定性,所以主要把放火事件类型分为五类:

存储放火:包括Redis、MongoDB、ES、MySQL等错误量和耗时的放火。

依赖服务放火:包括下游调用超时、抛异常等。

消息放火:主要是针对MQ的放火,包括减少Consumer、增加Producer发送耗时等。

服务器放火:主要包括CPU、内存等服务器资源放火。

网络放火:主要包括网络带宽、网络节点的放火,例如前面提到的盲测。

由于放火&降级演练是定期举行的,所以每种类型的放火事件我们都有机会尝试。例如,我们可以选择依赖服务放火类型,即线上通过经纬度反查城市ID的服务耗时比平常翻一倍这一放火事件。

确定燃烧半径

燃烧半径即放火范围,燃烧半径的选择一定要十分小心,不能过小,否则效果不明显,不能过大,否则将影响线上业务和用户,当然还是建议从小到大,逐步调整,比如这次我们选择燃烧半径为线上10%的经纬度反查城市ID的服务。

制定预案

一旦放火开始,线上应该具备哪些预案?哪些预案将自动生效?哪些预案需要人工干预?这一块要提前想清楚并整理好,特别是终止预案,即当发生什么情况或接收到什么告警时应该立即停止放火,预案梳理也是工程师站在更高视角来审视整个系统风险点的机会。

确定计划

确定好放火时参与的团队和人员,以及及时知会其他支撑团队,通知客服和业务方等。确定好时间,初期可以选择业务低峰期放火,条件成熟以后,可以逐渐往业务高峰期迁。

开始放火

你肯定会问怎么去放火?放火当然要借助工具,例如阿里开源的混沌工具ChaosBlade就不错,我们也是利用它来实现放火,放火架构图如下:

图的右侧是业务系统集群,每个模块的机器上都会安装一个放火Agent,用来接收和实施放火指令,并收集必要的数据,放火Agent如何实施放火指令呢?答案就在ChaosBlade中,内部实际上是使用JVM agent的注入能力(参见:https://blog.csdn.net/manzhizhen/article/details/100178857);而左侧的放火平台提供了放火的操作功能界面以及一些简单的数据大盘。由于我们使用了Dubbo,所以放火平台需要从Dubbo注册中心取服务拓扑,而为了放火平台能做得更通用,所以有个dubbo-fire模块进行服务拓扑的适配和转化等,还提供缓存功能。

可以看到,整体的放火架构还是很简单的,目前滴滴的放火平台还处在快速迭代中。

记住一点,一旦达到终止放火的条件(例如影响的用户数或系统指标超过预先确定的阈值),一定要及时的停止放火。

记录和分析结果

我们需要记录系统在放火过程中的表现、对业务的影响、预案的效果等,然后进行讨论和分析,这是不是我们想要的?怎么做才能让该紧急事件对系统和业务指标的影响更小?

我们需要把所有的放火演练沉淀下来,这些和历史的线上事故一样,是值得反复研究和学习的,特别是对于新同学。

4.
总结
就如我们前面说的,放火&降级演练是稳定性建设中少有的“主动”抓手,它里面蕴含了很多实践理论,需要我们在演练过程中不断学习和沉淀;放火&降级演练也是工程师和自己所建系统关于“非功能特性”的一次深入互动,这种经验在后续日趋复杂的服务端系统建设中尤为重要。
--------- PUHUI NOTION ---------
本文作者
-
易振强
滴滴 | 专家工程师

我是易振强,热爱开源,热爱分享,深耕分布式系统和稳定性建设,欢迎关注SDS服务降级系统:https://github.com/didi/sds ;也热爱生活,热爱漫画,一拳超人和海贼王都很好看!!

编辑 | 钱维
-
推荐阅读

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存