四.源码二
-
ChaosMonkeyScheduler
在ChaosMonkeyConfiguration中,如果要启动定时器,要有taskScheduler这个bean,否则无法启动
@Bean
public ChaosMonkeyScheduler scheduler(@Nullable TaskScheduler scheduler, ChaosMonkeyRuntimeScope runtimeScope) {
ScheduledTaskRegistrar registrar = null;
if (scheduler != null) {
registrar = new ScheduledTaskRegistrar();
registrar.setTaskScheduler(scheduler);
}
return new ChaosMonkeyScheduler(registrar, assaultProperties, runtimeScope);
}
public ChaosMonkeyScheduler(ScheduledTaskRegistrar scheduler, AssaultProperties config, ChaosMonkeyRuntimeScope runtimeScope) {
this.scheduler = scheduler;
this.config = config;
this.runtimeScope = runtimeScope;
if (scheduler == null) {
LOGGER.warn("No ScheduledTaskRegistrar available in application context, scheduler is not functional");
}
reloadConfig();
}
public void reloadConfig() {
//获取cron表达式
String cronExpression = config.getRuntimeAssaultCronExpression();
boolean active = !"OFF".equals(cronExpression);
if (currentTask != null) {
LOGGER.info("Cancelling previous task");
currentTask.cancel();
currentTask = null;
}
if (active) {
//如果应用里没有tasksheduler这个bean则抛错
if (scheduler == null) {
// We might consider an exception here, since the user intent could clearly not be serviced
LOGGER.error("No scheduler available in application context, will not process schedule");
} else {
//把ChaosMonkeyRuntimeScope下的攻击全部交给定时任务,但是只有两种方式内存和杀死应用两种攻击
CronTask task = new CronTask(runtimeScope::callChaosMonkey, cronExpression);
currentTask = scheduler.scheduleCronTask(task);
}
}
}
2.AssaultProperties
public class AssaultProperties implements Serializable {
@Value("${level : 5}")
@Min(value = 1)
@Max(value = 10000)
//级别,表示概率,比如level为1,那么1/(level+1)的概率
private int level;
@Value("${latencyRangeStart : 1000}")
@Min(value = 1)
@Max(value = Integer.MAX_VALUE)
//延迟时间范围起始值
private int latencyRangeStart;
@Value("${latencyRangeEnd : 3000}")
@Min(value = 1)
@Max(value = Integer.MAX_VALUE)
//延迟时间范围结束值
private int latencyRangeEnd;
@Value("${latencyActive : true}")
//延迟攻击是否生效
private boolean latencyActive;
@Value("${exceptionsActive : false}")
//异常攻击是否生效
private boolean exceptionsActive;
@AssaultExceptionConstraint
//自定义异常
private AssaultException exception;
@Value("${killApplicationActive : false}")
//是否kill应用
private boolean killApplicationActive;
@Value("${memoryActive : false}")
//内存攻击是否生效
private volatile boolean memoryActive;
@Value("${memoryMillisecondsHoldFilledMemory : 90000}")
@Min(value = 1500)
@Max(value = Integer.MAX_VALUE)
//内存攻击持续时间
private int memoryMillisecondsHoldFilledMemory;
@Value("${memoryMillisecondsWaitNextIncrease : 1000}")
@Min(value = 100)
@Max(value = 30000)
//每次上升内存间隔时间
private int memoryMillisecondsWaitNextIncrease;
@Value("${memoryFillIncrementFraction : 0.15}")
@DecimalMax("1.0")
@DecimalMin("0.0")
//每次上升剩余内存百分比
private double memoryFillIncrementFraction;
@Value("${memoryFillTargetFraction : 0.25}")
@DecimalMax("0.95")
@DecimalMin("0.05")
private double memoryFillTargetFraction;
@Value("${runtime.scope.assault.cron.expression:OFF}")
//定时任务cron表达式
private String runtimeAssaultCronExpression;
@Value("${watchedCustomServices:#{null}}")
//监听的服务
private List<String> watchedCustomServices;
}
3.WatcherProperties
public class WatcherProperties implements Serializable {
//是否对cotroller进行切面
@Value("${controller:false}")
private boolean controller;
//是否对restController进行切面
@Value("${restController:false}")
private boolean restController;
//是否对service进行切面
@Value("${service:true}")
private boolean service;
//是否对repository进行切面
@Value("${repository:false}")
private boolean repository;
//是否对component进行切面
@Value("${component:false}")
private boolean component;
}
4.ChaosMonkeyConfiguration
public class ChaosMonkeyConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(ChaosMonkeyConfiguration.class);
private final ChaosMonkeyProperties chaosMonkeyProperties;
private final WatcherProperties watcherProperties;
private final AssaultProperties assaultProperties;
public ChaosMonkeyConfiguration(ChaosMonkeyProperties chaosMonkeyProperties, WatcherProperties watcherProperties,
AssaultProperties assaultProperties) {
this.chaosMonkeyProperties = chaosMonkeyProperties;
this.watcherProperties = watcherProperties;
this.assaultProperties = assaultProperties;
try {
String chaosLogo = StreamUtils.copyToString(new ClassPathResource("chaos-logo.txt").getInputStream(), Charset.defaultCharset());
LOGGER.info(chaosLogo);
} catch (IOException e) {
LOGGER.info("Chaos Monkey - ready to do evil");
}
}
@Bean
@ConditionalOnClass(name = "io.micrometer.core.instrument.MeterRegistry")
public Metrics metrics() {
return new Metrics();
}
@Bean
public MetricEventPublisher publisher() {
return new MetricEventPublisher();
}
@Bean
//配置ChaosMonkeySettings,所有配置都在这
public ChaosMonkeySettings settings() {
return new ChaosMonkeySettings(chaosMonkeyProperties, assaultProperties, watcherProperties);
}
@Bean
//配置延迟攻击bean
public LatencyAssault latencyAssault() {
return new LatencyAssault(settings(), publisher());
}
@Bean
//配置异常攻击bean
public ExceptionAssault exceptionAssault() {
return new ExceptionAssault(settings(), publisher());
}
@Bean
//配置杀死应用bean
public KillAppAssault killAppAssault() {
return new KillAppAssault(settings(), publisher());
}
@Bean
//配置内存攻击bean
public MemoryAssault memoryAssault() {
return new MemoryAssault(Runtime.getRuntime(), settings(), publisher());
}
@Bean
//配置请求作用域
public ChaosMonkeyRequestScope chaosMonkeyRequestScope(List<ChaosMonkeyRequestAssault> chaosMonkeyAssaults, List<ChaosMonkeyAssault> allAssaults) {
return new ChaosMonkeyRequestScope(settings(), chaosMonkeyAssaults, allAssaults, publisher());
}
@Bean
//定时任务,注意自己注入taskScheduler bean
public ChaosMonkeyScheduler scheduler(@Nullable TaskScheduler scheduler, ChaosMonkeyRuntimeScope runtimeScope) {
ScheduledTaskRegistrar registrar = null;
if (scheduler != null) {
registrar = new ScheduledTaskRegistrar();
registrar.setTaskScheduler(scheduler);
}
return new ChaosMonkeyScheduler(registrar, assaultProperties, runtimeScope);
}
@Bean
//运行时作用域
public ChaosMonkeyRuntimeScope chaosMonkeyRuntimeScope(List<ChaosMonkeyRuntimeAssault> chaosMonkeyAssaults) {
return new ChaosMonkeyRuntimeScope(settings(), chaosMonkeyAssaults);
}
@Bean
@Conditional(AttackControllerCondition.class)
//配置controller切面
public SpringControllerAspect controllerAspect(ChaosMonkeyRequestScope chaosMonkeyRequestScope) {
return new SpringControllerAspect(chaosMonkeyRequestScope, publisher());
}
@Bean
@Conditional(AttackRestControllerCondition.class)
//配置restController切面
public SpringRestControllerAspect restControllerAspect(ChaosMonkeyRequestScope chaosMonkeyRequestScope) {
return new SpringRestControllerAspect(chaosMonkeyRequestScope, publisher());
}
@Bean
@Conditional(AttackServiceCondition.class)
//配置service切面
public SpringServiceAspect serviceAspect(ChaosMonkeyRequestScope chaosMonkeyRequestScope) {
return new SpringServiceAspect(chaosMonkeyRequestScope, publisher());
}
@Bean
@Conditional(AttackComponentCondition.class)
//配置component切面
public SpringComponentAspect componentAspect(ChaosMonkeyRequestScope chaosMonkeyRequestScope) {
return new SpringComponentAspect(chaosMonkeyRequestScope, publisher());
}
@Bean
@Conditional(AttackRepositoryCondition.class)
//配置respository切面
public SpringRepositoryAspect repositoryAspect(ChaosMonkeyRequestScope chaosMonkeyRequestScope) {
return new SpringRepositoryAspect(chaosMonkeyRequestScope, publisher());
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
//配置restEndPoint,提供对外web服务
public ChaosMonkeyRestEndpoint chaosMonkeyRestEndpoint(ChaosMonkeyRuntimeScope runtimeScope, ChaosMonkeyScheduler scheduler) {
return new ChaosMonkeyRestEndpoint(settings(), runtimeScope, scheduler);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
public ChaosMonkeyJmxEndpoint chaosMonkeyJmxEndpoint() {
return new ChaosMonkeyJmxEndpoint(settings());
}
}
五.yml配置
chaos:
monkey:
#是否开启混沌工程
enabled: true
assaults:
#攻击级别,表示概率,具体也就是2/(level+1)
level: 1
#开启延迟攻击
latencyActive: true
#开启异常攻击
exceptionsActive: true
#自定义异常
exception:
#指定自定义
type: pl.piomin.services.customer.ZuoqiException
arguments[0]:
className: java.lang.String
value: "这是自定义异常"
#开启kill应用攻击
killApplicationActive: true
#开启定时任务,需要taskSh
runtime-assault-cron-expression: 5/20 * * * * ?
#延迟时间范围结束
latency-range-end: 2000
#延迟时间范围开始
latency-range-start: 100
#开启内存攻击
memory-active: true
#内存攻击时剩余内存比例,例如内存攻击前freeMemory为200M,攻击后会剩200*0.2
memory-fill-increment-fraction: 0.2
#内存攻击持续时间
memory-milliseconds-hold-filled-memory: 1500
#内存攻击每次吃掉的内存比例,例如内存攻击前freeMemory为200M,在达到200*0.2M前,每次吃掉内存
memory-fill-target-fraction: 0.05
#内存攻击每次吃掉的内存间隔时间
memory-milliseconds-wait-next-increase: 100
#watchedCustomServices: [ "pl.piomin.services.customer.controller.CustomerController.findById"]
}
watcher:
#监控配置
repository: true
restController: false
management:
endpoint:
chaosmonkey:
enabled: true
endpoints:
web:
exposure:
include: health,info,chaosmonkey