查看原文
其他

去哪儿旅行混沌工程落地实践

于海影 Qunar技术沙龙 2023-04-08

作者介绍



于海影

2014年加入去哪儿旅行,测试开发工程师,负责去哪儿机票服务端测试,21年开始负责混沌工程在去哪儿的推广落地,致力于依托混沌工程进行质量缺口探测和建设。

一、前言

去哪儿的混沌工程依托 chaosblade 作为故障注入工具,在经历两年多的落地实践后已建成较成熟的体系。核心亮点包括:无损演练、自动化止损、全链路完整探测、可视化报告输出等。本文将从以下4方面阐述去哪儿旅行基于以上能力进行微服务架构下的系统强弱依赖演练以及攻防演练的成功实践:
  1. 先进行价值分析,什么样的公司适合落地混沌工程,混沌工程能得到什么收益;

  2. 介绍去哪儿旅行的混沌工程平台是什么样的架构;

  3. 怎样落地自动化闭环演练;

  4. 攻防演练,通过在线上突袭注入故障,锻炼技术的问题排查能力和验证故障预案体系。
二、价值分析

2.1 背景

2.1.1 历史上重大的宕机事故

首先,先看一下历史上的几个重大宕机事故:
  • 图一是 facebook 服务器宕机,持续时间7h,造成600多亿美元的市值损失。
  • 图二是韩国三大通信供应商 KT 发生故障,导致韩国大面积断网,直接影响到民生。
大家看到这类问题肯定都是吃瓜心态,但是作为技术,除了幸灾乐祸之外,还会有点危机意识,因为这类问题,不知道哪天就会轮到我们身上。那么发生类问题时,有没有什么好的解决方案呢?通过本篇文章,我们来解决这类问题。
(图一)

(图二)
2.1.2 复杂的集群
这里列举去哪儿旅行一些数据,线上跑着的活跃的应用有 3000 多个,dubbo 接口有 18000 多个,网关上注册的域名有 3500 多个,qmq13000 多个,技术栈有 5 种语言,大规模的系统群和生态很难保证完全可靠,任意一个系统有问题,都可能影响最终的结果。
2.1.3 复杂的基础设施
除了复杂的集群之外,还有另一种情况,现有的基础设施层规模和复杂度日益增加,100%的稳定性是很难达到的,那么发生问题时,怎么保证用户端的业务能更好的运转?这时需要强有力的技术保障。
2.1.4 常见故障类型
我们按常见的故障原因,将故障划分为以下几类:

1.机房问题:机房断电、网络不通、 网络延迟

2.中间件问题:zk集群故障、mq故障、 数据库故障、缓存故障

3.机器问题:load高、cpu满、 磁盘满、IO满

4.应用问题:fullGC、服务下线、 日志拖慢、线程池满

5.依赖问题:下游dubbo/http接口延迟、抛异常
基于这一系列的背景,混沌工程诞生了,下面我们来看下混沌工程的概念。
2.2 混沌工程概念
混沌工程是一门在分布式系统上进行实验的学科,它通过主动演练,提前把可能发生的问题,让它真实发生,看看系统的反应,进而提前应对,提前做出修改、提前做好应急预案。
2.3 混沌工程目标
混沌工程目标有两个,一是通过混沌工程,让我们建立起抵御生产环境中,发生不可预估问题的信心。做完之后,系统就是相对可靠的。不是靠概率和运气;二是把以前概率性的问题变成确定性的问题,混沌工程做到什么程度,就知道系统可靠到什么程度。
2.4 混沌工程收益
混沌工程收益主要如下,可以分三个角度来看:
第一个是人,对用户来说,可以享受更稳定的用户体验,以去哪儿旅行为例,如果系统挂了,用户想买票,或者退票一直不成功,就会影响用户出行,影响公司形象。对于开发和测试来说也是一样的,能够提前发现这些隐患并修复,提升故障的应急响应效率;
第二是流程上,完善了故障处理体系,把故障从被动发现转为主动发现,并且验证了报警是否真实有效;
第三是系统维度,提升了系统的韧性,最大限度地保证系统的可靠性。
从这个角度看,非常有必要落地混沌工程。去哪儿旅行是从19年开始落地混沌工程平台,一路上我们是分阶段去落地实施,下面就和大家具体介绍下去哪儿旅行混沌工程平台。
三、混沌工程平台
首先我们来看下我们公司的应用架构。从下至上,依次是机房层、中间件、服务器层、应用、服务依赖层。层次间会显示明显的关系,越往下,出问题的概率越小,但是造成的影响越大;越往上,出问题的概率越大,但单次产生的影响会相对小些。这意味着要落地混沌工程时,面临一个选择,你希望先落地哪些类型呢?我们的情况是从下向上进行的。下面就看下具体的实践路径。
1、关机演练:机房、中间件、实体机、虚拟机
首先我们做的是关机演练,关机演练意味着机器或机房需要先挂掉,这会涉及到各个方面。例如演练 A 机房挂掉的场景,如果没经过混沌工程演练,我们没有办法保证 A 机房挂掉时,对线上是没有影响的。很多开发在进行应用设计的时候是不会自觉考虑系统的可用性的。举个例子:某个应用部署了两个实例放在两个机房甚至一个机房,这个机房发生故障时,有两种情况:第一种,在同一个机房部署两个实例的,那么这两个就都挂了,依赖这个服务提供的能力都是不可用的;第二种情况,两个实例部署在两个机房,一个机房挂掉意味着一半的实例都没有了,没有做好容量规划和评估的话,上来的流量会一下把剩下的实例打爆。所以综合各种原因我们优先做的是关机演练。 
2、应用演练:服务依赖故障
第二个阶段是进行应用的强弱依赖演练,我们线上经常会面临这种情况:比如某一个服务 A ,调用下游的服务 B ,超时时间设置的不合理导致出问题。我们设置超时时间的时候尽可能保证请求能回来,会在最长时间的界线上留一定的buffer,当大量的响应时间都涨到阈值之上时,系统可能会被拖死,机器的资源都用于等待下游的响应,导致不能服务新的请求,这种情况如果不好好处理的话 ,就会导致别人的服务出了问题,它没有影响,但是你可能被拖死。 
3、攻防演练:常态化攻防 混沌文化
第三个阶段是攻防演练,通过常态化的攻防演练,提升大家的故障意识和故障处理能力。下面就分别介绍下每个演练的能力和关键点。
3.1 关机演练

3.1.1 目标

同一机房某个业务线所有服务节点全部关机,演练规模是单次超过一千台。

3.1.2 关键点

  • 有完善的应用画像平台,将应用机房信息聚合起来,方便查询,方便应用改造;

  • 通知机制,及时周知进度和问题;

  • 真实的关机;

  • 接入报警,核心指标有问题要自动熔断;

  • 开机后,自动重启服务。

3.1.3 流程

3.1.4 效果

  • 机房演练:49次 4000+机器 应用500+个 发现10+问题/次。
  • 关机演练:71次 3000+机器 应用250+个。

3.2 应用强弱依赖演练

3.2.1 技术选型

应用级别的演练就会涉及到技术选型的问题,因为应用级别的演练需要的场景非常多,例如 fullgc 、日志写入慢,依赖超时或者抛指定异常等,需要比较好的技术手段去支持,当时维护比较好、用的比较多的有三种类型:第一种是官方的,支持平台是虚拟机,场景比较丰富,问题是不开源。二是 chaosblade ,阿里巴巴开关的演练工具,特点是容器和 kvm 都支持,场景相对丰富,并且是开源的,三是 chaosmesh,这个也是开源的,但是只支持 k8s 模式。综合考虑后,我们最终选用的是 chaosblade 。
组件
支持平台
支持场景
开源
整体性
侵入型
特点
ChAP
VM
丰富
实验参照对比
Chaosblade
VM/K8S
丰富
差(当时只有agent)
简单易用、扩展性好、社区活跃
Chaos Mesh
K8s
丰富
云原生、社区活跃

chaosblade 支持多层面的故障演练,比如基础资源层面的、应用服务层面的。同时还支持 k8s 。并且它支持的场景非常丰富,基本上涵盖了需求的各个方面,但是还有一写场景是缺失的。主要如下:

  • HTTP超时

  • fullgc

  • 日志拥堵

  • 调用点区分

  • 链路匹配
对于这些不支持的场景,在落地的过程中,我们支持了这些形态,并且将这些改动提交到社区,参与开源共建。

3.2.2 目标

弱依赖挂掉,主流程不受影响

3.2.3 关键点

1、依赖关系收集
依赖关系收集的主要来源有两种:一种是应用的 access.log ;另一种是 zk 上的服务注册信息。我们把这些信息汇集到一个分析聚合的服务中,它会每天更新七日内的数据,并把这些数据聚合之后生成的依赖关系存在 db 里。强弱依赖信息需要用户进行标记,演练平台提供依赖关系的标记和查询服务。
2、故障注入编排
一个演练,通常都需要注入多个故障,这就需要一定的编排策略。编排策略主要有三种:
  • 并行:一次把所有的故障都注入到服务上,这种方式的好处是比较快;缺点是,出了问题,不好排查,多个故障间容易有干扰。

  • 串行:每个服务上,同时只会有一种故障,出了问题之后比较好排查。

  • 手工控制:可以根据需要去选择,比较灵活。

3.2.4 流程

1、整体流程
强弱依赖演练的整体流程,分为四个阶段:

第一阶段:先进行依赖关系收集。

第二阶段:用户在演练平台人工标记强弱依赖关系。

第三阶段:进行真实演练。

第四阶段:演练后问题修复,修复之后重新在进行标记、演练,形成闭环。
2、详细流程

通过这样一个流程,保证演练顺利进行,形成闭环。

3.2.5 效果

演练系统 68 个,工时 69.5PD ,发现问题 136 个。


通过演练,我们发现了大量的系统问题。建设完这项能力之后, 我们希望扩大生效面,获得更高的收益。怎么样能把影响面扩大呢,面临的问题就是,人工梳理标记演练比较耗时,一个应用大约1PD,那么我们就在思考自动化的执行方案,下面就详细介绍下自动化闭环演练。
3.3 自动化闭环演练
3.3.1 目标
常用常新,避免运动式可靠性保证,将人工成本降到最低,将覆盖面提升到最大。
3.3.2 难点
1、完善的应用元数据
首先来看下应用元数据采集,大家要知道,我们要做自动化的演练的话,那么我们在演练前,就需要知道所有的应用依赖信息。因为只有知道了所有的信息,我们才可以提前做演练场景的编排,我们有完善的应用元数据分析平台,分析好所有的底层资源,http、dubbo、db、以及应用本身暴露出来的各种接口信息,包括接口和数据类型;还有 qtrace 和拓扑关系等,有了这些信息后,聚合到一起,我们就能分析出依赖的明细数据是什么样的,有了这些数据之后,我们就可以将演练场景自动化的创建出来,进行故障注入。


2、自动化执行的流量和断言
故障注入之后,流量怎么获取呢,我们一期人工演练的时候,是直接用的线上真实的用户流量。用线上真实流量影响范围不好控制,会对用户产生真实影响,所以我们一般都是在业务低峰,大半夜进行演练。自动化演练,如果还是直接用线上流量,风险会非常大。这个时候就需要有其他的流量帮助触发这些流程,并且保证能够得到结果。比较好的是,我们有完善的接口自动化平台和压测平台,通过压测和自动化平台,将流量执行到目标机器上,得到自动化的断言结果。下图是自动化闭环演练的详细的流程 首先混沌平台通过应用信息平台获取依赖信息,进行故障场景的编排。接下来通过压测和自动化平台,获取流量,将流量执行到目标机器上,同时混沌控制平台,对演练环境进行故障注入。压测平台,从应用的入口,发起请求后,会拿基准环境和测试环境的 response ,调用 diff 平台,进行 response 数据的接口对比。并把对比的的结果返回给混沌控制平台,混沌控制平台进行最终的强弱依赖结果判断,产出可视化的演练报告。介绍完流程后,我们来看下,在落地自动化闭环演练的过程中的几个关键点。

3.3.3 关键点
1、case 筛选策略,保证依赖命中率
先来解释下依赖命中的概念,在故障注入期间,有压测流量打到当前的依赖,才算命中。下图是某一个入口依赖的的拓扑图,我们的演练范围是要覆盖整个链路的每一个接口的,如果要保证命中率,那 case 筛选逻辑就很重要,我们希望的是通过筛选之后,能保证命中率在 90% 以上,这样演练才是有效果的。case 筛选策略有两种,第一种是从入口处的应用,随机取若干条,从入口开始请求,这个方式比较简答粗暴,但是问题是覆盖率很难保证。举个例子,比如说用户在我们平台买机票,它可以买北京到上海的单程,也可以买北京到上海的往返。单程和往返这两种类型的报价,在服务端,是不同的系统来提供服务的,如果我随机筛选的 case 里,只有单程的请求,没有往返的请求,那就只能命中单程的链路,往返这条链路上的所有依赖就都没办法命中。第二种策略是精确匹配,比如系统 d 调用系统 e 提供的接口 f ,准确的找到系统 d 调用系统 e 的 f 接口的 trace,和入口做关联,发起请求,这样就能保证依赖被覆盖到。
2、熔断恢复策略
熔断主要是靠监控报警来实现的。这里面有两个逻辑,第一个是指标标记存储逻辑,演练前,我们人工去标记业务线的核心面板、以及应用的核心监控,将这些核心指标存储起来做为熔断指标。第二个是演练时的异常匹配逻辑,演练时我们查看熔断指标如果有报警,就终止演练,非熔断指标会在演练界面记录并周知。
3.3.4 效果
已经完成 10 个入口,3820 个依赖的自动化闭环演练。

3.4 攻防演练

3.4.1 背景

前面介绍的,关机演练、强弱依赖演练、自动化闭环演练,这些都是想办法提前发现系统问题,把故障发生的可能性降低,但是我们没有办法保证线上 100%  不出故障,那么故障发生时,有没有什么方法能帮助我们快速的定位故障原因,让故障快速恢复呢,攻防演练就就是为了解决这方面的问题而产生的

3.4.2 目标

提升技术同学故障处理能力 完善故障应急预案体系。

3.4.3 方案

攻击方注入攻击点,防守方排查出异常后上报给攻击方,攻击方确认攻击点是否正确正确则得分。
攻防演练的系统架构,基本上是复用的自动化闭环演练那套,用压测的打标流量,在线上环境进行故障注入和恢复。
3.4.4 流程
1、攻击点编排:选择历史高频故障进行场景设计。
2、攻击点上报:防守方定位排查后,上报给攻击方 攻击方确认,正确则得分。
3、攻击终止:防守方定位成功或者超时自动终止。
4、积分:根据定位时长、故障难易程度进行积分排名、公示
5、复盘:过程中发现的问题进行修复

3.4.5 后续计划

后续我们计划,把范围扩大,进行常态化的攻防,培养大家的风险意识,同时进行整个业务线或者整个公司层面的大型攻防,建立固定的攻防日,建立混沌文化。


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

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