ChaoBlade 的实现原理
Posted zuozewei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ChaoBlade 的实现原理相关的知识,希望对你有一定的参考价值。
一、混沌工程的定义
根据混沌工程的principles,里面这样定义了:
Chaos Engineering is the discipline of experimenting on a system in
order to build confidence in the system’s capability to withstand
turbulent conditions in production.
中文翻译是这样的:
混沌工程是在分布式系统上进行实验的学科, 目的是建立对系统抵御生产环境中失控条件的能力以及信心。
英文中似乎没有分布式系统这个字眼,看来中文翻译的时候把范围说小了。
它有原则描述:
- 建立一个围绕稳定状态行为的假说
- 多样化真实世界的事件
- 在生产环境中运行实验
- 持续自动化运行实验
- 最小化爆炸半径
看着有些比较新鲜的词还挺有意思。也有人把它和异常测试、故障测试啥的给区分开来说明。要说还是得整概念,概念还是要先于技术的发展,给技术指导一个方向,而落地嘛,总是需要一些时间的。
据说阿里的 chaosblade 开源工具算是具有混沌工程特点的工具。下面看一下它的功能。
二、下载并解压
这个工具非常简单,下载解压就能用。
[gaolou@7dgroup2 ~]$ wget -c https://github.com/chaosblade-io/chaosblade/releases/download/v0.2.0/chaosblade-0.2.0.linux-amd64.tar.gz
[gaolou@7dgroup2 ~]$ tar zxvf chaosblade-0.2.0.linux-amd64.tar.gz
三、使用及实现
1、模拟CPU负载
[gaolou@7dgroup2 chaosblade-0.2.0]$ ./blade create cpu fullload
{"code":200,"success":true,"result":"cb6300fd4899c537"}
[gaolou@7dgroup2 chaosblade-0.2.0]$
查看模拟效果:
通过上图可以看到确实实现了us CPU 使用率消耗的效果。
再来看一下它是怎么实现的。
burnCpu 这个方法里的。关键源码如下:
func runBurnCpu(ctx context.Context, cpuCount int, cpuPercent int, pidNeeded bool, processor string) int {
args := fmt.Sprintf(`%s --nohup --cpu-count %d --cpu-percent %d`,
path.Join(util.GetProgramPath(), burnCpuBin), cpuCount, cpuPercent)
if pidNeeded {
args = fmt.Sprintf("%s --cpu-processor %s", args, processor)
}
args = fmt.Sprintf(`%s > /dev/null 2>&1 &`, args)
response := channel.Run(ctx, "nohup", args)
if !response.Success {
stopBurnCpuFunc()
bin.PrintErrAndExit(response.Err)
}
if pidNeeded {
// parse pid
newCtx := context.WithValue(context.Background(), exec.ProcessKey, fmt.Sprintf("cpu-processor %s", processor))
pids, err := exec.GetPidsByProcessName(burnCpuBin, newCtx)
if err != nil {
stopBurnCpuFunc()
bin.PrintErrAndExit(fmt.Sprintf("bind cpu core failed, cannot get the burning program pid, %v", err))
}
if len(pids) > 0 {
// return the first one
pid, err := strconv.Atoi(pids[0])
if err != nil {
stopBurnCpuFunc()
bin.PrintErrAndExit(fmt.Sprintf("bind cpu core failed, get pid failed, pids: %v, err: %v", pids, err))
}
return pid
}
}
return -1
}
其他关联的代码就不帖了。总的来说,就是写了一个小程序把 CPU 消耗掉,这个功能一个 do while 就可以了。
2、模拟IO高
[root@7dgroup2 chaosblade-0.2.0]# ./blade create disk burn --write --read --size 10 --count 1024 --timeout 300
{"code":200,"success":true,"result":"f026b3510722685d"}
查看模拟效果:
[root@7dgroup2 chaosblade-0.2.0]#
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 91.00 250.00 815.00 84892.00 92588.00 333.30 43.92 39.27 41.60 38.56 0.93 99.50
dm-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-7 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 1.00 105.00 496.00 865.00 98012.00 92692.00 280.24 43.72 34.02 33.40 34.37 0.73 99.40
dm-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-7 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.99 106.93 259.41 675.25 99853.47 91750.50 410.00 36.22 38.53 47.09 35.24 1.06 98.81
dm-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-7 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 80.00 241.00 1103.00 116340.00 82296.00 295.59 44.06 33.03 47.92 29.78 0.74 99.90
dm-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-7 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
从上面的结果来看,确实把 IO 给消耗掉了。下来我们看看它是怎么实现消耗的。
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
24036 be/4 root 104.55 M/s 0.00 B/s 0.00 % 99.99 % dd if=/dev/vda1 of=/dev/null~ iflag=dsync,direct,fullblock
24034 be/4 root 0.00 B/s 104.55 M/s 0.00 % 68.17 % dd if=/dev/zero of=/tmp/chao~bs=10M count=1024 oflag=dsync
通过查看 io 高的进程就可以看到这两个进程。也就是说,chaosblade 调用 dd 实现的 IO 高模拟。关键实现代码如下:
// write burn
func burnWrite(size, count string) {
for {
args := fmt.Sprintf(`if=/dev/zero of=%s bs=%sM count=%s oflag=dsync`, tmpDataFile, size, count)
response := channel.Run(context.Background(), "dd", args)
channel.Run(context.Background(), "rm", fmt.Sprintf(`-rf %s`, tmpDataFile))
if !response.Success {
bin.PrintAndExitWithErrPrefix(response.Err)
return
}
}
}
// read burn
func burnRead(fileSystem, size, count string) {
for {
// "if" arg in dd command is file system value, but "of" arg value is related to mount point
args := fmt.Sprintf(`if=%s of=/dev/null bs=%sM count=%s iflag=dsync,direct,fullblock`, fileSystem, size, count)
response := channel.Run(context.Background(), "dd", args)
if !response.Success {
bin.PrintAndExitWithErrPrefix(fmt.Sprintf("The file system named %s is not supported or %s", fileSystem, response.Err))
}
}
}
一个读一个写。
四、总结
这个 chaosblade 实际上可以看做是一个工具集,集成了各种小工具。
混沌的帽子在这个工具,现在套着还是有点大。要想用它来实现上千上万个节点的模拟,还需要各种集成配置,远程执行等工具的配合。
大家再回过头来看看上面写的混沌工程定义的原则。这些模拟有没有符合这些原则呢?如果各位有处理生产环境的经验的话,会知道,这样的模拟,其实和真实环境下的 CPU 高、IO 高的逻辑还是有不同的。
通常我们说一个应用程序的在CPU高的情况下是否能保持健壮。有两种含义:
-
其他程序在消耗CPU较高的情况下,被测试的程序是否能保持健壮。
-
是指的是这个应用本身的代码消耗了大量CPU的情况下,被测试程序是否能保持健壮。
有处理过生产类似问题的朋友们会知道,第一种情况,除了部署上的不合理会出现之外,几乎是看不到的。chaosblade其实是模拟的这种情况。而第二种情况,chaosblade 现在还是做不到的。
但第二种情况却是测试过程中的重点。
其实英文中的 chaos 的含义是混乱。这和中文的混沌是非常不同的概念,现在这个概念被翻译成混沌,真是拉低了混沌这个词本身该有的寓意。
以上是关于ChaoBlade 的实现原理的主要内容,如果未能解决你的问题,请参考以下文章
[Chaoblade]jvm-sandbox UnsupportedOperationException错误
[Chaoblade]jvm-sandbox UnsupportedOperationException错误
[Chaoblade]jvm-sandbox UnsupportedOperationException错误