四.源碼二
-
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:
#攻擊級別,表示概率,具體也就是1/(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