查看原文
其他

云原生混沌工程平台Chaos Mesh原理与实践

The following article is from VCEC Author VCEC




PingCAP R&D云原生混沌工程专家周志强带来《云原生混沌工程平台Chaos Mesh原理与实践》精彩议题,演讲结合PingCAP近几年来在混沌工程方向的探索,从混沌工程的概念出发,讲述如何从零开始构建云原生混沌工程平台Chaos Mesh以及云原生对混沌工程带来的机遇和挑战。


1、混沌工程与云原生应用
 
1.1 分布式系统越来越复杂

下方是亚马逊和NETFLIX服务依赖的一个结构图,正常人都不可能完全去了解这么复杂的系统。同时这么复杂系统后面肯定会有非常薄弱的环节。而且这些薄弱的环节随时都会都有可能发生故障。
 
1.2 混沌工程

定义:混沌工程是一门新兴的技术学科,他的初衷是通过实验性的方法,让人们建立对于复杂分布式系统在生产中抵御突发事件能力的信心。


混沌工程和这些传统测试方法的主要区别在于:混沌工程是发现新信息的实践过程,而故障注入则是对一个特定的条件、变量的验证方法。

 
1.3 云原生

定义:云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展 的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。


云原生技术应用特点:
1)容器化
2)Kubernetes
3)弹性:快速伸缩、为失败设计、优雅降级
 
但是其中就会有一个问题:我们如何验证这种为失败设计和优雅降级,它同时是符合预期工作的呢?这个时候我们就需要我们可以运用混沌工程来验证这一点。比较简单的一句话来说,混沌工程就是通过失败来避免失败。

混沌工程还有故障演练,我自己认为混沌过程和故障演练存在区别的。故障演练是一段时间去做一次,但是混沌工程应该是一个不断持续的闭环
 
2Chaos Mesh 设计与实现

首先我们说我们建立一个稳态,然后在稳态上面做一个假设,比如说我们一个系统中的几个机器,我们直接把它去掉,那么这个系统它会不会 down掉或者说它是否还能按照预期正常工作,或者是降级到一个预期的降级状态。
 
以上是我们做的假设,然后我们进行混沌实验。混沌实验执行后,对假设进行验证,在验证以后可能得到一个积极或者消极的结果,根据这个结果我们再去提升我们当前的应用。这也就意味着后面工程,并其实不是说大家凑在一块,做一次大规模的故障演练就结束了,而是需要测试运维以及开发全部一起来完成一项非常繁重的工程。
 
我们平台在开始之初就是非常注重混沌工程。因为我们做的是分布式的一个数据库,最开始是也是人肉直接拔网线的方式模拟网络故障。后来我们内部也已经出了一个叫做薛定鄂的系统。薛定鄂的系统其实是跑了一堆测试在上面,在跑这些测试的同时给它注入各种故障,来验证这个系统它真的是work的。再到后来,从薛定鄂中我们孵化出了Chaos Mesh。
 
2.1 所以什么是Chaos Mesh呢?

Chaos Mesh是一个开源的云原生混沌工程平台,它其实目前的主要功能是是支持混沌实验的注入与编排,同时易用,可视化操作。
 
2.2 Chaos Mesh的功能
 
 
可以发现和刚才提到应用层面的混沌注入不太一样,我们这边主要是注重于 note级别的一些比如说 pod-kill.然后网络还可以提到文件系统、时间的偏移、cpu-burn 的一些压力等等。现在还在加入一些对于云厂商的支持;还有也在支持JVMChaos,到了比较硬核的环节。
 
2.3 云原生的代表技术

我们看到加红色的部分提到了几个点,就是容器不可变,基础设施和声明式的API,这三点我觉得是目前我们开始在设计和实践中比较沾光的几个地方。

 
2.4 相关技术

  • 容器:容器它是用来资源的隔离,然后我们也可以用它来限制爆炸半径
  • 不可变基础设施:稳定地分发 Release
  • 声明式 API:让用户明确表示他想要的预期状态
  • 其实在 API的设计上下了很大的功夫,可以让用户真正描述出真正想要的东西。
 
2.5 Chaos Mesh 整体架构
 
这是Chaos Mesh的一个整体架构,最上面是user,然后最下面是我们真正一个节点,可以看到用户通过 kubectl apply、 client apply还有Kubernetes API server可以输入他预期想要的case,然后也可以通过这两个组件来观测它当前的case的状态。往下是Chaos Controller Manager,他监听资源的变化,然后决定现在或者说以后要不要进行故障的注入以及故障的恢复。然后再往下一层是Chaos Daemon,负责在具体节点上进行故障注入。

2.6 使用 Kubernetes API/Client

2.7 Chaos Dashboard和资源变化的监听
 
友好的用户界面、接入 RBAC 的权限管控、方便管理和观察已有的错误。

2.8 Reconcile
 

Reconcile 以 ReplicaSet 为例

 


2.9 *Chaos 如何注入?
2.10 Cgroup 影响资源分配
  • CPU:限制 CPU 资源分配
  • Memory:限制 内存 资源分配
  • Pid:限制 Pid 数量资源的分配
 


3、侵入 namespace
 
3.1 Namespace 影响查询过程
 
下一个比较难做的其实是如何进入 namespace, namespace会影响查询的过程。
mnt namespace:影响 path resolution
pid namespace:影响 process lookup
net namespace:影响 network device lookup
 
举个例子,如果mnt namespace不一样的话,我们在里面看到的文件是不一样的;pid namespace不一样的话,我们看到的进程是不一样的。net namespace不一样的话,我们看到的那些网卡那些网络设备是不一样的。
 
3.2 Linux namespace and Go Don’t Mix

而且还有一个问题就是Linux namespace和Go其实兼容性不是很好。你会发现,明明已经把goroutine已经绑定了,但是被绑定的模式还是去克隆了另外一个thread出来, thread继承了以前namespace,这样就会造成 Namespace的泄露。Namespace 泄漏会导致其他线程的 Namespace 难以追踪。

如果禁止,Go进程将会变得十分不可控,所以这样是不可行的。那么有没有其他的方式实现?当然是有的。
 
3.3 nsenter的问题

nsenter 的问题
信号处理较为随意,难以跟踪子进程;难以应对 mnt namespace 的情形:nsenter --mnt /proc/xxx/ns/mnt cat
nsenter: failed to execute cat: No such file or directory,这一情形在 Distroless 容器逐渐流行的今天更加普遍了。
 
3.4 不同的解决方案
3.5 侵入 namespace
nsexec --net=/proc/xxx/ns/net iptables -A …..
nsexec --net=/proc/xxx/ns/net tc qdisc add ….
nsexec --pid=/proc/xxx/ns/pid stress-ng …
nsexec --mnt=/proc/xxx/ns/mnt inject ...
 
 

4、从流程中注入

4.1 以(入方向)限流为例:tc qdisc
 
我们举一个以网络流量入方向的限流为例,这个名字叫traffic control,FIFO。它是提供了一些策略,我们可以简单的把它理解为一些管道给它提供了先进先出,然后带优先级的先进先出以及令牌统姓。我们其实要用的就是令牌桶这个功能,使用iptables和ipset,把我们想要被限制的流量给它筛选出来,然后转到特定的 qdisc中就完成了网络的限流。


4.2 以文件系统注入错误为例
 
如果一个用户的应用程序想读取一个文件的话,它其实是通过一连串的操作来完成的。我们需要从这一连串的操作中找出一个我们可以注入的点。做几个假设,我们可以从EXT4这边注入,然后我们可以从FUSE这边注入,当然也可以从提供一个自定义的驱动来注入,也甚至可以我们做一个case硬件来注入,当然越往下的话我们的效果越好,但是成本越高。

 
我们目前使用的是在FUSE这一层面进行注入。
 
 
这个图是当一个进程被注入的时候一个情况,可以看到 application是被注入的进程。
 

4.3 替换已经打开的资源
 

4.4 以时间偏移为例

`clock_gettime` syscall (228 on x86_64);
`clock_gettime` vDSO call;
Language/Runtime specific function call
  • Rust: `Instant::now()`
  • Go: `time.Now()`
  • C: `clock_gettime` in glibc
  • Java: `System.currentTimeMillis()` or `Instant.now()`
  • ...

4.5 language/runtime 专门的函数调用

 
4.6 什么是 vDSO?

由kernel 提供在用户态运行的函数的机制:clock_gettime、getcpu、gettimeofday、time;
一段由 kernel 在程序启动时分配的内存区域;
这部分内存的内容和动态链接库的 ELF 格式一致。
 
4.7 如何完成注入?
`PTRACE_ATTACH` 容器中的每一个进程
`PTRACE_POKEDATA` 修改 vDSO 中时间相关函数的实现
`PTRACE_DETACH`
 

5、使用案例
 
5.1 小鹏汽车

  • 使用 Chaos Mesh:测试监控告警系统;模拟低网络延迟情况;
  • 覆盖监控测试系统 100%;
  • 通过使用 Chaos Mesh 减少路试 成本 90%。
 
5.2 网易伏羲实验室

  • 测试组件(redis rabbitmq scheduler) 3+;
  • 目前发现的潜在问题 20+。

关注本公众号,回复 “Chaosmesh” 获取本次分享的、完整的PPT。

链接:



继续滑动看下一个

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

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