Spring/Springboot 是使用非常广泛的 JAVA 框架,所以通过使用 chaostoolkit 的插件 chaostoolkit-spring
来进行 springboot restful api 的混沌工程实验.
pip install -U chaostoolkit-spring
首先这个实验依赖于chaos-monkey-spring-boot 这个项目,chaos toolkit 通过具有这个 lib 报的 springboot 项目交换。
这个交互主要是通过 spring boot actuator HTTP endpoints 进行。
所以在进行 chaos 实验之前,我们先添加一个 springboot 的项目来做模拟:创建 spring 项目不具体展开, 几个关键点是:
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>chaos-monkey-spring-boot</artifactId>
<version>2.0.2</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</exclusion>
</exclusions>
</dependency>
spring.profiles.active=chaos-monkey
chaos.monkey.enabled=true
chaos.monkey.watcher.controller=false
chaos.monkey.watcher.restController=true
chaos.monkey.watcher.service=true
chaos.monkey.watcher.repository=false
@GetMapping("/HelloWorld/{id}")
public BaseResponse getHelloWorld(@PathVariable Long id) {
return BaseResponse.OK().data(HelloWorldDTO.builder().id(id).msg("Hello World").build());
}
@PostMapping("/HelloWorld")
public BaseResponse<HelloWorldDTO> createHelloWorld(@RequestBody HelloWorldDTO requestBody) {
return BaseResponse.OK().data(requestBody);
}
@PutMapping("/HelloWorld/{id}")
public BaseResponse<HelloWorldDTO> updateHelloWorld(@PathVariable Long id, @RequestBody HelloWorldDTO updateData) {
return BaseResponse.OK().data(updateData);
}
@DeleteMapping("/HelloWorld/{id}")
public BaseResponse<HelloWorldDTO> deleteHelloWorld(@PathVariable Long id) {
return BaseResponse.OK().data(HelloWorldDTO.builder().id(id).msg("deleted!").build());
}
GET: http://localhost:8080/actuator/chaosmonkey
如果有返回说明设置成功了:
{
"chaosMonkeyProperties": {
"enabled": true
},
"assaultProperties": {
"level": 5,
"latencyRangeStart": 1000,
"latencyRangeEnd": 3000,
"latencyActive": true,
"exceptionsActive": false,
"exception": {
"type": null,
"arguments": null
} ......
}
}
spring experiment:
{
"version": "1.0.0",
"title": "springboot-chaos-monkey try",
"description": "springboot chaos monkey usage",
"tags": [
"springboot"
],
"steady-state-hypothesis": {
"title": "Application responds",
"probes": [
{
"type": "probe",
"name": "call localhost url hello world",
"tolerance": 200,
"provider": {
"type": "http",
"timeout": 3,
"url": "http://localhost:8080/HelloWorld/1"
}
}
]
},
"method": [
{
"name": "configure_assaults",
"provider": {
"arguments": {
"base_url": "http://localhost:8080/actuator",
"assaults_configuration": {
"level": 5,
"latencyRangeStart": 2000,
"latencyRangeEnd": 5000,
"latencyActive": true,
"exceptionsActive": false,
"killApplicationActive": true,
"restartApplicationActive": false
}
},
"func": "change_assaults_configuration",
"module": "chaosspring.actions",
"type": "python"
},
"type": "action"
}
],
"rollbacks": [
{
"name": "disable_chaosmonkey",
"provider": {
"arguments": {
"base_url": "http://localhost:8080/actuator"
},
"func": "disable_chaosmonkey",
"module": "chaosspring.actions",
"type": "python"
},
"type": "action"
}
]
}
结果:
(chaos-toolkits) ➜ chaos-toolkits git:(master) ✗ chaos run spring-experiment.json
[2019-05-21 14:38:00 INFO] Validating the experiment's syntax
[2019-05-21 14:38:00 INFO] Experiment looks valid
[2019-05-21 14:38:00 INFO] Running experiment: springboot-chaos-monkey try
[2019-05-21 14:38:00 INFO] Steady state hypothesis: Application responds
[2019-05-21 14:38:00 INFO] Action: enable_chaosmonkey
[2019-05-21 14:38:00 CRITICAL] Steady state probe 'enable_chaosmonkey' is not in the given tolerance so failing this experiment
[2019-05-21 14:38:00 INFO] Let's rollback...
[2019-05-21 14:38:00 INFO] Rollback: disable_chaosmonkey
[2019-05-21 14:38:00 INFO] Action: disable_chaosmonkey
[2019-05-21 14:38:00 INFO] Experiment ended with status: failed
chaos-spring 代码分析, 实际上 chaos-spring 代码不多,很容易理解
✗ tree .
.
├── __init__.py
├── actions.py
├── api.py
└── probes.py
实际上总过就是这三个文件.
api: 文件是访问 api chaos-monkey 的接口调用
probes: 用来定义 probes 的方法,下面的例子这个就可以在 experiment.json 中定义了 assaults_configuration
可以使用在
```python
def assaults_configuration(base_url: str,
headers: Dict[str, Any] = None,
timeout: float = None,
configuration: Configuration = None,
secrets: Secrets = None) -> Dict[str, Any]:
"""
Get the current assaults configuraton from the specified service.
"""
response = api.call_api(base_url=base_url,
api_endpoint="chaosmonkey/assaults",
headers=headers,
timeout=timeout,
configuration=configuration,
secrets=secrets)
if response.status_code != codes.ok:
raise FailedActivity(
"ChaosMonkey assaults enquiry failed: {m}".format(m=response.text))
return response.json()
简单使用 spring 的这个介绍就到这里,后续会进行说明如何使用 actions/probes 原理的介绍.