ChaosBlade使用与Java自定义故障注入实现

ChaosBlade使用与Java自定义故障注入实现

  • 前言
  • ChaosBlade介绍
  • 安装
  • 功能介绍
    • java agent挂载
    • 停止实验&uid卸载
    • UID查询
    • 通用参数查询
    • 指定类方法注入延迟
    • 修改指定类方法的返回值
    • 指定java进程CPU满载
    • 指定jvm区域内存溢出
    • CodeCache
    • 指定类方法抛自定义异常
    • 指定类方法执行自定义java或groovy脚本(重要)
      • 脚本规范
      • 执行命令

前言

当前团队考虑通过一些故障注入或者故障模拟的方式来进行故障分析的测试.因此选择了ChaosBlade来进行技术实现.

ChaosBlade介绍

阿里开源的混沌实验实施工具
支持Java 应用、C++ 应用、Docker 容器、云原生平台等
其中的Chaosblade-exec-jvm模块,基于jvm-sandbox(https://github.com/alibaba/jvm-sandbox)
ChaosBlade的具体介绍可以到这里了解: https://github.com/chaosblade-io/chaosblade/blob/master/README_CN.md

安装

开箱即用,下载最新版release版本解压可用(记得配置环境变量或临时环境变量)
下载地址: https://github.com/chaosblade-io/chaosblade/releases
当前下载版本chaosblade-1.4.0,解压可得下图内容,通过blade执行命令
ChaosBlade使用与Java自定义故障注入实现_第1张图片

功能介绍

chaosblade支持两种调用方式:CLI 和 HTTP
cli即客户端模式,http即url调用模式,以下给出http示例,本文主要基于cli模式的jvm场景使用

//启动http服务,在指定端口,开放给功能调用
blade server start -p 端口号  
//执行 CPU 满载实验 注意:此处的%20是url空格
curl "http:/xxxx:9526/chaosblade?cmd=create%20cpu%20fullload"

java agent挂载

执行场景命令之前,需要先挂载java agent,此操作需要一点点时间
操作成功,会返回实验准备的UID
命令: blade prepare jvm --pid {java进程pid}

[root@JXQVKDSAP04 test]# blade prepare jvm --pid 26383
{"code":200,"success":true,"result":"7b2893ef0b180fab"}

在卸载实验时会用到此处返回的UID

停止实验&uid卸载

实验执行完毕,停止场景
命令: blade destroy {场景UID}

[root@JXQVKDSAP04 test]# blade destroy e02bb5bc8792ced9
{"code":200,"success":true,"result":{"target":"jvm","action":"script","flags":{"classname":"cn.xxx.community.activity.controller.GuessController","methodname":"queryTop","script-file":"/home/test/ChaoTools.java","script-name":"ChaoTools"}}}

卸载UID
命令: blade revoke {实验UID}
简写: blade r {实验UID}

[root@JXQVKDSAP04 test]# blade r 7b2893ef0b180fab
{"code":200,"success":true,"result":"success"}

UID查询

当忘记UID时,可以通过此命令查询
命令: blade status --type prepare --target jvm
简写: blade s --type p --target jvm

[root@JXQVKDSAP04 test]# blade s --type p --target jvm
{
        "code": 200,
        "success": true,
        "result": [
                {
                        "Uid": "7b2893ef0b180fab",
                        "ProgramType": "jvm",
                        "Process": "",
                        "Port": "25855",
                        "Pid": "17682",
                        "Status": "Revoked",
                        "Error": "",
                        "CreateTime": "2021-12-29T14:36:58.917334484+08:00",
                        "UpdateTime": "2021-12-29T16:08:38.856833797+08:00"
                }
        ]
}

通用参数查询

不同的场景有专属的参数,具体参数可以在场景命令中查询,通过此命令可以查询通用的参数
所有的命令都可以添加-h查看帮助文档
命令: blade create jvm 或 blade create jvm.md

[root@JXQVKDSAP04 test]# blade create jvm.md
Create a chaos engineering experiment

Usage:
  blade create [command]

Aliases:
  create, c

Examples:
blade create cpu load --cpu-percent 60

Available Commands:
  cplus       C++ chaos experiments
  cpu         Cpu experiment
  cri         CRI experiment
  disk        Disk experiment
  docker      Docker experiment
  druid       Experiment with the Druid
  dubbo       Experiment with the Dubbo
  es          ElasticSearch experiment!
  file        File experiment
  gateway     gateway experiment!
  hbase       hbase experiment!
  http        http experiment
  jedis       jedis experiment
  jvm         Experiment with the JVM
  k8s         Kubernetes experiment
  kafka       kafka experiment
  lettuce     redis client lettuce experiment
  log         log experiment
  mem         Mem experiment
  mongodb     MongoDB experiment
  mysql       mysql experiment
  network     Network experiment
  process     Process experiment
  psql        Postgrelsql experiment
  rabbitmq    rabbitmq experiment
  redisson    redisson experiment
  rocketmq    Rocketmq experiment,can make message send or pull delay and exception
  script      Script chaos experiment
  servlet     java servlet experiment
  strace      strace experiment
  systemd     Systemd experiment
  tars        tars experiment

Flags:
  -a, --async             whether to create asynchronously, default is false
  -e, --endpoint string   the create result reporting address. It takes effect only when the async value is true and the value is not empty
  -h, --help              help for create
  -n, --nohup             used to internal async create, no need to config
      --uid string        Set Uid for the experiment, adapt to docker and cri

Global Flags:
  -d, --debug   Set client to DEBUG mode

Use "blade create [command] --help" for more information about a command.

指定类方法注入延迟

命令: blade create jvm delay

#对xx类中的xxxname方法注入延迟4s故障
blade c jvm delay --time 4000 --classname=xxx.xxx.xxxclass --methodname=xxxname --process tomcat

修改指定类方法的返回值

返回值类型仅支持基本类型、null、和String
命令: blade create jvm return

#将xx类中的xxxname方法的返回值修改为hello-world
blade c jvm return --value hello-world --classname xxxxclass --methodname xxxname --process tomcat

指定java进程CPU满载

命令: blade create jvm cpufullload
简写: blade c jvm cfl

#全满载
blade c jvm cfl --process tomcat 
#指定2核满载
blade c jvm cfl --cpu-count 2 --process tomcat

指定jvm区域内存溢出

支持HEAP,NOHEAP,OFFHEAP,用Heap来表示Eden+Old,用NOHEAP来表示metaspace,用OFFHEAP来表示堆外内存
命令: blade create jvm OutOfMemoryError
简写: blade c jvm oom

#堆空间内存溢出
blade c jvm oom --area HEAP --wild-mode true --process tomcat
#元数据空间内存溢出
blade c jvm oom --area NOHEAP --wild-mode true --process tomcat

CodeCache

CodeCache主要用于存放native code,其中主要是JIT编译后的代码。被JIT编译的一般都是“热代码”,简单说就是调用频率比较高的代码,JIT编译后,代码的执行效率会变高,CodeCache满会导致JVM关闭JIT编译且不可再开启,那么CodeCache满会引起系统运行效率降低,导致系统最大负载下降,当系统流量较大时,可表现为RT增高、QPS下降等
命令: blade create jvm CodeCacheFilling
简写: blade c jvm ccf

blade c jvm CodeCacheFilling --process tomcat

指定类方法抛自定义异常

命令: blade create jvm throwCustomException
简写: blade c jvm throwCustomException
简写: blade c jvm tce

#xxx类的xx方法抛出Exception异常,影响次数2
blade c jvm throwCustomException --exception java.lang.Exception --classname xxxx.class --methodname xxxname --process tomcat --effect-count 2

指定类方法执行自定义java或groovy脚本(重要)

通过自己编写脚本的方式,可以实现复杂的故障注入,例如篡改参数、修改返回值、抛自定义异常等

脚本规范

  1. 必须创建一个类,类中必须提供public Object run(Map
    params)方法,入参params即目标方法的入参,可以通过params.get(“0”),params.get(“1”)方式获取目标方法的第1、第2个入参,也可以通过params.put(“0”,xx)来修改目标方法的入参
  2. 类中的依赖必须是目标类中已有的类
  3. 同包下的类引用,必须写全包名,比如故障脚本类是com.example.controller.ExceptionScript类中引入了同包下的DubboController类,则DubboController必须添加com.example.controller.DubboController.引入非同包下的类,无需写全包名
  4. public Object run(Map params)方法如果返回值不是null,则会修改目标方法的返回值(类型需要与目标方法返回值类型一致)
/**
 * 自定义故障注入测试类
 * @Author: QQQ
 * @Date: 2021/12/29 10:37 上午
 */
public class ChaoTools {

	/**
	 * chaos 默认必须要实现的方法
	 */
	public Object run(Map<String, Object> params) {
		// 调用内存溢出模拟方法
		oomHeadTest();
		// 返回值,修改原方法的返回值. 返回null 不修改返回值
		return null;
	}
	/**
	 * 内存溢出模拟
	 */
	private void oomHeadTest(){
		System.out.println("进入oom_head_test");
		String randomTxt = "dushdpo9ahdpoaihdpsahdyioandupoiund;oiauern;obvolrsybzlryewrwerkbiwuebyreisuyr";
		List<Object> list = new ArrayList<>();
		while (true){
			randomTxt += randomTxt;
			// 自定义对象(目标类中也有此对象的依赖)
			Guess guess = new Guess();
			guess.setId(UUID.randomUUID().toString());
			guess.setTitle(randomTxt);
			list.add(guess);
		}
	}
}

执行命令

命令: blade create jvm script

--effect-count string   影响的请求条数
--effect-percent string 影响的请求百分比
--script-content string 脚本文本内容,是Base64编码后的内容,不能和script-file同时使用
--script-file string    脚本文件,文件绝对路径
--script-name string    脚本名称,日志记录用,可不填写
--script-type string    脚本类型,取值为java或groovy,默认为java

示例:

#目标类xxxxclass下的xxxname方法,执行脚本/home/test/ChaoTools.java
[root@JXQVKDSAP04 test]# blade c jvm script --classname cn.xxx.xxx.activity.controller.GuessController --methodname queryTop --script-file /home/test/ChaoTools.java --script-name ChaoTools
{"code":200,"success":true,"result":"e02bb5bc8792ced9"}

此时调用cn.xxx.xxx.activity.controller.GuessController#queryTop接口,则会出现内存溢出,自定义故障注入实现

你可能感兴趣的:(Java基础,问题排查,JVM,java,开发语言,后端)