✪ 2.2.1 快速定位
很多同学第一次面对问题或者故障时,往往头脑空白不知从何查起,如果碰到大故障时,很多主管在后面围观,心情则会更加紧张,进一步拖慢了查问题的时间,那么如何对线上的故障和问题进行快速定位呢?
首先,在定位问题之前,要快速的确认是不是属于本域的问题,很多时候问题的表象看似出自于自己的应用,但实则可能是上下游、中间件或者硬件问题引起的,如果方向错误,可能会拖延故障的处理时间,放大线上影响和故障等级,那么如何快速定位,我认为可以从变更的角度去入手思考:
- 本域是否发生过变更?这个是最核心的判断因素之一,如果没有,那很大可能跟本域的关系不大,请注意,这个变更不仅仅是通常理解上的代码发布、配置推送、数据操作等,而是所有可能会对线上的运行环境产生影响的操作,如代码中的配置推送,上下线或置换容器等;当然,并不是说没有变更就完全没关系,有些情况也有例外,举几个常见的例子:
- 属于定时任务、延时执行等变更后一段时间才运行的链路。
- 由于流量评估不准,平时流量较少,但某一时间段峰值流量突然剧增的链路。
- 上线前测试不足或上线后流量较少,业务覆盖面不全的链路,可能由于突然的冷门流量导致报错。
本质上来说,这些情况产生的错误还是由于“变更”引起的,只不过是变更生效的时间被延后了。
- 如果发现存在变更,那么要结合大盘,判断故障的时间线是否与变更的时间线吻合或相差不大,如果是的话那么就八九不离十了。
在定位到产生问题的域后,如果不是自己的问题,那么可以尽量协助排查,如果是域内产生的问题,那么就要着手开始定位根因,这个时候就是考验稳定性同学的基本功和经验了,同时也要结合集团给出的一些比较好的产品化工具,例如:
⍟ 监控大盘
常见的监控系统有很多,一些开源的监控大盘让我们面对大多数问题时基本不需要去机器上命令行排查了,对于不同的场景,用对了监控可以事半功倍。
阿里内部有各种各样的大盘,可以让集团的同学在处理问题时的速度更快,同样部分开源的大盘也非常强大,至于如何做产品选型,大家可以自行评估,思路大概就是如下几种大盘:
- 硬件 & 中间件指标大盘:从容器硬件水位、中间件(RPC、缓存、DB...)水位等偏重于技术指标的大盘中,通过时间线定位出问题的大致方向和时间线。
- 链路追踪大盘:以传输协议、接口作为维度,找出相关的链路和trace,具体问题具体排查。
- 流量调度系统:偏重于单机大盘的系统,可以从秒级维度查出单台容器的性能指标,并可以实现流量调度,将有问题的容器流量摘除。
⍟ 分布式日志系统
对于一些代码层面或业务层面的报错,单纯通过大盘进行深度定位是不现实的,究其根因还是要到底层去查日志报错堆栈,这个时候就需要用到分布式日志系统了,通过分布式日志系统采集的信息,可以配置相应的大盘,或直接搜索错误堆栈,进行细节上的排查。
✪ 2.2.2 快速止血 & 恢复
之前将问题划分为高可用以及数据问题,那么也按照这个分类来讲一下对应的止血 & 恢复策略:
⍟ 高可用问题
止血与恢复在高可用问题上,大多数情况是相关联的,止血即恢复,如:
- 某系统变更导致应用夯死,回滚重启的同时,系统恢复正常,达到了止血和恢复效果。
- 推送某开关,导致业务链路阻塞,回滚开关后,链路恢复正常。
- 由于网络服务商原因,导致某地域的机房网络重传率过高,通过切流其他单元达到了恢复止血。
同时,相信大家都接触过高可用问题,对于这类问题的快恢也有一定的了解,限于篇幅原因这里就不再一一描述不同高可用问题的恢复策略了,直接在这里引用和拓展一下之前总结过的高可用问题快恢六招:
- 切流:遇到天灾人祸等不可避免的地域性故障,应对单元维度,机房维度,机器维度切流;业务层面上要提前布防,通过集团提供的diamond、switch等配置中心进行代码熔断。
- 扩容:流量暴增时对集群进行扩容,适用于流量超出预期的场景。
- 限流:接口限流可以从入口层面保护绝大部分流量,热点限流可以保障流程中涉及的中间件或者下游不被打挂。
- 回滚:较为直接的止血方式,回滚前需先机房隔离或切容灾,防止回滚时间较长升级故障。
- 降级:若是链路弱依赖,先降级再排查。
- 重启:应对内存溢出,fullgc连接数满等。
⍟ 数据问题
数据问题与高可用问题有非常大的差异,高可用问题恢复起来较为简单,通常有比较明确的策略,但数据问题则不同,我将其分为两类:
- 数据计算错误:由于线上逻辑问题导致数据计算错误,进而阻断链路或产生脏数据。
- 数据存储错误:持久化与非持久化的数据存储内容与期望值出现偏离,如商品价格落库错误、缓存数据错误等,导致链路上读到的都是脏数据,产生数据不一致或资损问题。
其中,数据计算错误的恢复策略较为简单,可以直接通过熔断、切流等机制关闭增量问题来源来进行恢复止血,数据问题真正的难点在于存储错误,非持久化的数据存储,如缓存,可以通过熔断增量问题入口,清除存量数据来解决,但是一旦持久化的数据脏掉且量级非常大的话,从数据的提取到数据的回滚都非常的困难:
- 数据提取:
- 量级大:在很多情况下,回滚数据需要提取非常大量的数据,提取速度很慢。
- 复杂程度高:模型比较复杂的系统,提取数据时需要非常复杂的过滤规则,且经常出现提取到一半时发现过滤规则有问题的情况,这时候之前提取的数据就无用了,进一步加长恢复的时间。
- 数据实时性:如果没有数据留痕系统,那么提取数据最常见的方式就是从ODPS中捞取,即天表或小时表,但是这两种表都会有数据延迟,即从产出数据表的时刻起,到当前的时刻为止,如果数据发生过变化,那么离线表中是无法获取到的,也就是从离线表中拿到的是脏数据,会导致一批数据回滚不准,产生二次故障。
- 数据回滚:
- 风险高:提取出的数据如果不准,回滚将直接出现二次故障,进一步加大数据回滚的难度。
- 性能问题:当回滚的数据量过大,需要一个产品化程度比较高的数据订正平台做控速、灰度控制、失败重试以及进度管控,否则订正速度一旦过快,可能直接击穿链路节点。
因此,数据存储问题或我们常见的资损问题,往往主要关注的不是恢复时间,而是主动发现率、止血时间、资损金额等,因为要快速恢复量级很大的数据存储问题是不现实的,往往都是依赖人为提取数据以及手动恢复,事实上针对数据存储问题,也没有系统能做到通用化的数据回滚策略,因为每个业务、每个系统的提取数据,回滚数据的逻辑基本都是不同的,如果依赖平台通用逻辑回滚,那么二次故障的概率会非常高,所以说,对于数据存储问题,要做到第一时间通过熔断、切流等机制止血后,在优先保证数据绝对正确的情况下,再进行回滚恢复,不能盲目的追求恢复时间。
2.3 反哺
✪ 2.3.1 复盘 & Action 跟进
每一次故障都是血的教训,但是以我的视角来看,发生故障并不完全是一件坏事,因为应用系统是人造就的,是人就一定会犯错,所以系统也不可能保证百分之百的强壮,有问题则证明系统、流程还有不足,才能推动我们不断的向前进步,这也是我们每一次故障之后要进行复盘的原因,犯了错并不怕,重要的是如何改正。
集团对于故障的复盘有一套严格的执行流程,大概如下图所示:
具体详细的复盘流程不详细展开,谈谈我认为复盘这个节点比较重要的几个问题:
⍟ 三省吾身
无论是自己,亦或是团队其他同学导致的故障,一定要问自己几个问题:
- 为什么:背景是什么,故障是怎么发生的?根因是什么?为什么当时没发现?
- “我”:
- 就是我:这个故障是我导致的,我当时怎么处理的这个问题?恢复的快不快?还有没有可以改进的地方了?
- 如果是我:他这次产生的故障,如果放在我身上,我会不会跟他做一样的事情?如果要我来恢复,我应该怎么做?
- 下一步:这次的故障暴露了什么问题?是代码bug还是流程问题导致的?我可以给团队提什么样的建议来解决这个问题?
- 动手去做:确定解法,我可不可以帮助团队同学去做完这件事情,会对我自己有多少成长?
⍟ Action 落实
很多时候,我们都只局限在“这一次”的故障中,而不会去思考“每一次”。在我看来,Action真正的作用,不只是为了单纯的解决这一次的问题,而是要我们举一反三,从根因上思考,系统中是否还存在与这次故障相同的问题?我们要如何分类的去解决,这样才能真正的将这一次故障的效应和Action发挥最大的作用。
✪ 2.3.2 稳定性分享
除了稳定性的技术建设,文化宣导也是基础建设的一部分。
除了故障方面,稳定性同学所做的底层优化专项等偏向于技术层面的工作,也可以在团队内部或跨部门做分享,建立工程师文化,培养技术兴趣,以及扩大部门和团队在集团中的影响力,以我所在的商品团队举例,每月都会举行一次“工程师之夜”的分享会,包含技术、业务模型等比较有代表性的工作成果,同时团队内部优秀的同学也会经常跨域去做技术分享。
03
后记
稳定性工作远比文章里的内容要复杂的多,每一个单点拉出来,都能形成一篇文章去介绍,限于篇幅问题,无法将稳定性所有的内容表达出来,这里将我过去几个月的思考和大家分享,欢迎一起交流评论。最后,也向所有从事稳定性工作的同学致敬,希望各位都能在其中获得自己想要的成长和收获。
参考文章
1. 面向失败的设计-故障与攻防演练锤炼容灾应急能力
https://developer.aliyun.com/article/726337
2. 知乎:什么是混沌工程?Answer:亚马逊云科技
https://www.zhihu.com/question/308294657
3. 天启回归提效与精准测试
https://developer.aliyun.com/topic/n-cases?id=115120