目录
前言
案例
1、强弱依赖不合理
2、预案不生效
3、异常数据不兼容
4、监控体系缺陷
5、系统缺整体架构设计
总结
前言
我们公司从启动混沌工程到现在已经几乎覆盖了线上的所有核心业务,先后进行过2000次演练共挖掘出120个漏洞。这些漏洞有些得了及时修复避免了生产故障的发生,也有些因为各种原因推进缓慢没能在引爆之前得到修复,通过血泪教训验证了混沌工程的价值。本篇将通过梳理这120个漏洞以及我们混沌中发现的一些共性的问题拿来一起分享下,希望对大家有所帮助。
案例
1、强弱依赖不合理
我们在演练电商业务线时发现当某商品的库存服务不可访问时会导致该商品页无法正常打开,这是个典型的强弱依赖不合理的经典案例。
在应用场景中商品信息与库存信息应该是弱依赖,因为用户只是想浏览和了解商品而已,凭什么因为不知道有多少货就不给用户看了呢?库存信息与交易信息才是强依赖,当用户真正决定购买时才涉及到有多少货的问题。
这种强弱依赖不仅是代码端做好降级判断等问题,更理想的做法是做好服务拆分,从物理上进行节点的隔离,这样就能更好的根据强弱依赖进行不同等级的高可用设计。例如商品的评论服务节点对于所有的电商模块来说都是弱依赖,那我们就可以在评论相关的资源配备上采用更激进的策略节约成本。
2、预案不生效
案例场景:A调用B、B调用C,当B调用不到C时就用本地缓存获取数据返回给A。
这个场景中B的设计就是典型的利用缓存做降级的预案设计,每个研发可能都会信誓旦旦的表示这么简单的逻辑绝对不会有问题,但我们在实际的混沌演练中确实发现此类预案没有生效!不生效的原因基本都聚焦到对降级条件的判断上。B从C拿到不完整的数据要不要启用本地缓存?B到C网路延时、延时多少要用缓存?
3、异常数据不兼容
混沌工程在网络层面的故障注入常用的方法是模拟4层异常,例如域名解析错误、网络延时、通信丢包、网络不通等,这确实可以发现大部分因网络问题引发的故障,但不能发现7层引发的问题,例如异常的数据格式。
案例场景:A调用B,如果B返回200就从B的body中按协商好的Json格式进行解析。
那么问题来了,当B返回非200A会怎样?返回200但body无数据A会怎样?body有数据但Json格式与协商不一样会怎样?甚至说body返回的就不是一个Json会怎样?这些异常是真实会发生而且一定会发生的,那么演练一定要覆盖到,所以这里就需要用到7层的网络异常注入了。
4、监控体系缺陷
有个成语叫“手眼通天”,混沌工程中像ChaosBlade这类的异常注入工具只是我们的“手”,手帮我们造成混乱,但混乱造成的影响需要靠“眼”来看到,监控体系就是混沌工程的“眼”。手的能力和眼的视野决定了混沌演练效果的上限。 实践中发现很多时候我们的“眼”是有缺陷的,明明用户体验已经严重受损但我的监控健康度仍然100分;明明用户体验一切正常但我们的告警已经达到灾难级,或者演练时我们需要关注某些指标但我们提供不了,这些都是现有监控系统需要优化改造的点。
5、系统缺整体架构设计
案例:后端服务分别部署在两个集群节点,对接同一套数据库,前端通过主域名和备用域名的跨域名重试实现多节点容灾设计,当我们模拟主节点到数据库网络异常时,期望前端通过备用域名仍能提供稳定的用户体验。
如图:
经过演练发现用户的前端界面在卡顿6秒后才能正常展示,并不符合我们的预期,于是逐层去分析原因。
前端:先尝试主域名请求,因为不清楚后端服务是否具备幂等性所以必须等待后端明确返回非200的状态码后才能进行跨域名重试。
后端:数据库链接超时2秒,重试3次,3次都不成功返回500+。
前后端的设计都合情合理,甚至说无懈可击,但组合在一起就造成了这6秒延时,从系统架构来看明明可以快速失败进行跨域名重试,从而提高用户体验的,而这些设计并不是前端、后端具体某一个团队负责的,需要整体架构设计与相应的规范。
总结
混沌工程是一种产生新数据的技术,通过演练不仅能提前发现隐患避免故障的大范围爆发,还能发现运维体系的盲区和整体架构设计的缺陷,可以说混沌工程本身就是优秀架构设计的试金石。