hystrix熔断:熔断只是作用在服务调用这一端,只需改consumer端
1)熔断器开关相互转换的逻辑
a.服务的健康状况 = 请求失败数 / 请求总数.
b.熔断器开关由关闭到打开的状态转换是通过当前服务健康状况和设定阈值比较决定的
b1.关闭时, 请求被允许通过熔断器. 如果当前健康状况高于设定阈值, 开关继续保持关闭. 如果当前健康状况低于设定阈值, 开关则切换为打开状态
b2.打开状态, 经过一段时间后, 熔断器会自动进入半开状态, 这时熔断器只允许一个请求通过. 当该请求调用成功时, 熔断器恢复到关闭状态. 若该请求失败, 熔断器继续保持打开状态, 接下来的请求被禁止通过
c.保证服务调用者在调用异常服务时, 快速返回结果, 避免大量的同步等待
d.在一段时间后继续侦测请求执行结果, 提供恢复服务调用的可能
2)参数设置
a.circuitBreaker.requestVolumeThreshold //滑动窗口的大小,默认为20
b.circuitBreaker.sleepWindowInMilliseconds //过多长时间,熔断器再次检测是否开启,默认为5000,即5s钟
c.circuitBreaker.errorThresholdPercentage //错误率,默认50%
每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开
1)pom.xml:Feign中已经依赖了Hystrix,所以在maven配置上不用做任何改动
2)application.yml:
feign:
hystrix:
enable:true
3)启动类
@EnableFeignClients //开启feigin注解
@EnableCircuitBreaker //开启Hystrix
@EnableDiscoveryClient //开启注册中心
@SpringBootApplication //spring-boot启动
public class Application {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
注:还可用@SpringCloudApplication代替,@SpringCloudApplication包括以下注解: @Target({ElementType.TYPE}、@Retention(RetentionPolicy.RUNTIME)、@Documented、@Inherited、@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker
4)serviceImplement层
@HystrixCommand(fallbackMethod = "findOrderFallback", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")//timeoutInMilliseconds 使用线程隔离时,调用超时时间
})
public String findOrder(Long userId,String orderNo) throws InterruptedException {
Random random = new Random();
sleepRandom = random.nextInt(2000);
System.out.println("sleepRandom="+sleepRandom);
Thread.sleep(sleepRandom);
ConsumerBeehiveUser user = findById(userId);
if (user != null) {
return user.getUsername() + " 的订单" + orderNo + " 找到啦!sleepRandom="+sleepRandom;
}
return "用户不存在!sleepRandom="+sleepRandom;
}
public String findOrderFallback(Long userId, String orderNo) {
return "订单查找失败!sleepRandom="+sleepRandom;
}
参数说明:
a.快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。
b.请求总数下限:在快照时间窗内,必须满足请求总数下限才有资格根据熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用此时不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。
c.错误百分比下限:当请求总数在快照时间窗内超过了下限,比如发生了30次调用,如果在这30次调用中,有16次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%下限情况下,这时候就会将断路器打开。
fallback是降级处理
2.隔离:
1)启动类:
@SpringBootApplication
@EnableDiscoveryClient //开启eureka服务
@EnableFeignClients //开启feigin注解
@EnableCircuitBreaker //开启Hystrix @EnableCircuitBreaker或@EnableHystrix
@EnableHystrixDashboard //开启dashboard图形监控
public class ConsumerBeehiveApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
//用于调用"提供者"的方法
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerBeehiveApplication.class, args);
}
}
2)serviceimplement:
@HystrixCommand(fallbackMethod = "testCircuitBreakerFallback", commandProperties = {
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")//errorThresholdPercentage 断路器错误请求百分比
})
public String testCircuitBreaker(int id) {
if(id % 2 == 0 && id < 10) { // 直接返回
return "consumer testCircuitBreaker "+id;
} else { // 无限循环模拟超时
int j = 0;
while (true) {
j++;
}
}
}
public String testCircuitBreakerFallback(int id) {
String template = restTemplate.getForObject("http://provider-user/user/testCircuitBreaker/"+id, String.class);
return "fallback:"+template;
}
构建Hystrix的Command对象, 调用执行方法.
Hystrix检查当前服务的熔断器开关是否开启, 若开启, 则执行降级服务getFallback方法.
若熔断器开关关闭, 则Hystrix检查当前服务的线程池是否能接收新的请求, 若超过线程池已满, 则执行降级服务getFallback方法.
若线程池接受请求, 则Hystrix开始执行服务调用具体逻辑run方法.
若服务执行失败, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.
若服务执行超时, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.
若服务执行成功, 返回正常结果.
若服务降级方法getFallback执行成功, 则返回降级结果.
若服务降级方法getFallback执行失败, 则抛出异常.
配置参数说明
1.HystrixCommandProperties:HystrixProperty类型
1)Metrics
a.metricsRollingStatisticalWindowInMilliseconds:统计滚动的时间窗口,默认:5000毫秒(取自circuitBreakerSleepWindowInMilliseconds)
b.metricsRollingStatisticalWindowBuckets:统计窗口的Buckets的数量,默认:10个,每秒一个Buckets统计
c.metrics.rollingPercentile.enabled:是否开启监控统计功能,默认:true
d.metrics.rollingStats.timeInMilliseconds:
e.metrics.rollingStats.numBuckets:
f.metrics.rollingPercentile.timeInMilliseconds:
h.metrics.rollingPercentile.numBuckets:
i.metrics.rollingPercentile.bucketSize:
g.metrics.healthSnapshot.intervalInMilliseconds
h.circuitBreaker.requestVolumeThreshold:断路器请求阈值,熔断器在整个统计时间内是否开启的阀值,默认20。也就是在metricsRollingStatisticalWindowInMilliseconds(默认10s)内至少请求20次,熔断器才发挥起作用
2)Circuit Breaker
a.circuitBreaker.sleepWindowInMilliseconds:断路器休眠时间,熔断时间窗口,默认:5秒.熔断器中断请求5秒后会进入半打开状态,放下一个请求进来重试,如果该请求成功就关闭熔断器,否则继续等待一个熔断时间窗口
b.circuitBreaker.enabled:断路器开关,是否启用熔断器,默认true. 启动
c.circuitBreaker.errorThresholdPercentage:断路器错误请求百分比,默认:50%。当出错率超过50%后熔断器启动
d.circuitBreaker.forceOpen:断路器强制开启,是否强制开启熔断器阻断所有请求,默认:false,不开启。置为true时,所有请求都将被拒绝,直接到fallback
e.circuitBreaker.forceClosed:断路器强制关闭,是否允许熔断器忽略错误,默认false, 不开启
3)Execution
a.execution.isolation.semaphore.maxConcurrentRequests:使用信号量隔离时,命令调用最大的并发数,默认:10
b.execution.isolation.strategy:使用命令调用隔离方式,默认:采用线程隔离,ExecutionIsolationStrategy.THREAD
c.execution.isolation.thread.timeoutInMilliseconds:使用线程隔离时,调用超时时间,默认:1秒
d.executionIsolationThreadPoolKeyOverride:线程池的key,用于决定命令在哪个线程池执行
e.execution.isolation.thread.interruptOnTimeout:使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作.默认:true
f.execution.timeout.enabled:
4)Fallback
a.fallback.isolation.semaphore.maxConcurrentRequests:使用信号量隔离时,命令fallback(降级)调用最大的并发数,默认:10
b.fallback.enabled:是否开启fallback降级策略 默认:true
5)Request Context
a.requestLogEnabled:是否开启请求日志,默认:true
b.requestCacheEnabled:是否开启请求缓存,默认:true
2.HystrixCollapserProperties:HystrixProperty类型
1)maxRequestsInBatch:请求合并是允许的最大请求数,默认: Integer.MAX_VALUE
2)timerDelayInMilliseconds:批处理过程中每个命令延迟的时间,默认:10毫秒
3)requestCache.enabled:批处理过程中是否开启请求缓存,默认:开启
3.HystrixThreadPoolProperties:
1)corePoolSize:配置线程池大小,默认值10个. 建议值:请求高峰时99.5%的平均响应时间 + 向上预留一些即可
2)maxQueueSize:配置线程值等待队列长度,默认值:-1,建议值:-1,表示不等待直接拒绝,测试表明线程池使用直接决绝策略+ 合适大小的非回缩线程池效率最高.所以不建议修改此值。当使用非回缩线程池时,queueSizeRejectionThreshold,keepAliveTimeMinutes 参数无效
3)queueSizeRejectionThreshold:队列大小拒绝阈值
4)keepAliveTimeMinutes
5)metrics.rollingStats.timeInMilliseconds
6)metrics.rollingStats.numBuckets