分布式系统环境下,服务之间的依赖调动非常常见,一个业务调用通常依赖多个基础服务,如果调用某服务层,而这个服务层不可用或者因为网络等原因响应时间超出预期,请求线程被堵塞,当有大量的请求调用这个服务就会导致这个服务的资源被耗尽,无法继续对外提供服务,这也叫雪崩效应;
雪崩效应经常出现在,服务器宕机,光纤被挖断(如腾讯:https://baijiahao.baidu.com/s?id=1628812006479290058&wfr=spider&for=pc),异常流量,缓存穿透,JVM长时间FullGC,同步等待;
出现了雪崩效应,服务一个一个出问题,为了构建一个稳定可靠的分布式系统,我们的系统应该具备自我保护能力,避免雪崩效应;
QPS (Query per second 每秒查询率)
QPS: 经过全链路压测,计算单机极限QPS,集群 QPS = 单机 QPS * 集群机器数量 * 可靠性比率;
全链路压测 除了压 极限QPS,还有错误数量;
全链路:一个完整的业务流程操作;
本文猪角Hystrix就是解决同步等待导致的雪崩问题;
对来自依赖的延迟和故障进行防护控制,一般都是通过网络调用导致的;
快速失败并迅速恢复;
停止分布式系统中的级联故障;
回退并优雅的降级;
https://github.com/Netflix/Hystrix/wiki#what-is-hystrix-for
分布式系统中,各个系统错综复杂,一个系统依赖多个服务,一个服务出现问题,可能导致整个系统瘫痪;
官方文档写了,一个应用依赖30个微服务,并且他们可用率高达99.99%,得到以下结论:
99.99的30次方 = 99.7% 正常运行时间
如果有10亿次请求则有3,000,000次的失败请求
即使所依赖的30个服务都表现很棒,每个月还是有2小时的停机时间
https://github.com/Netflix/Hystrix/wiki#what-problem-does-hystrix-solve
原理图如下:
.execute():同步阻塞方式执行run()(HystrixObservableCommand无此方法)
.queue():异步非阻塞方式执行run()(HystrixObservableCommand无此方法)
.observe():事件注册前调用,run()/construct(),继承HystrixCommand,hystrix创建新线程非堵塞的执行run(),后者堵塞执行construct();注册成功则执行onNext()和onCompleted,失败则执行onError();
.toObservable():事件注册后调用,run()/construct();
这四个方法用来触run()/construct(),一个实例也只能执行一次,并且他们都会走toObservable()
其他不做过多介绍,如有兴趣参考https://github.com/Netflix/Hystrix/wiki/How-it-Works详细工作原理
start.spring.io引入actuator,web,hystrix
主程序入口添加,@EnableCircuitBreaker
新建FuckController,
1 package cn.cold.springcloudhystrixclientdemo.springcloudhystrixclientdemo.controller; 2 3 import com.netflix.hystrix.HystrixCommandGroupKey; 4 import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 5 import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; 6 import org.springframework.web.bind.annotation.GetMapping; 7 import org.springframework.web.bind.annotation.RestController; 8 9 import java.util.Random; 10 11 /** 12 * @author mengll 13 * @date 2019/5/21 10:33 14 */ 15 @RestController 16 public class FuckController { 17 private final static Random random = new Random(); 18 19 /** 20 * 当{@link #fuck} 方法调用超时或失败时, 21 * fallback 方法{@link #errorFuck()}作为替代返回 22 * 23 * @return 24 */ 25 @GetMapping("fuck") 26 @HystrixCommand( 27 fallbackMethod = "errorFuck", 28 commandProperties = { 29 @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", 30 value = "100") 31 } 32 ) 33 public String fuck() throws Exception { 34 // 如果随机时间 大于 100 ,那么触发容错 35 int value = random.nextInt(200); 36 System.out.println("errorFuck() costs " + value + " ms."); 37 Thread.sleep(value); 38 return "errorFuck"; 39 } 40 41 public String errorFuck() { 42 return "Fault"; 43 } 44 45 @GetMapping("fuck-2") 46 public String fuck2() { 47 return new FuckCommand().execute(); 48 } 49 50 /** 51 * 编程方式 52 */ 53 private class FuckCommand extends com.netflix.hystrix.HystrixCommand<String> { 54 55 protected FuckCommand() { 56 super(HystrixCommandGroupKey.Factory.asKey("fuck"), 57 100); 58 } 59 60 @Override 61 protected String run() throws Exception { 62 // 如果随机时间 大于 100 ,那么触发容错 63 int value = random.nextInt(200); 64 System.out.println("helloWorld() costs " + value + " ms."); 65 66 Thread.sleep(value); 67 68 return "Hello,World"; 69 } 70 71 //容错执行 72 protected String getFallback() { 73 return FuckController.this.errorFuck(); 74 } 75 } 76 }
启动访问fuck,多访问几次看效果
在启动信息中可以发现以下日志
Registered ‘/actuator/hystrix.stream‘ to hystrix.stream-actuator-endpoint
访问后,会发现一直ping
主程序入口添加,@EnableHystrixDashboard
启动后,访问http://localhost:9090/hystrix
然后将/actuator/hystrix.stream 输入到页面中
然后访问fuck,返回9090程序看到图
Command配置源码在HystrixCommandProperties,构造Command时通过Setter进行配置
1 //使用命令调用隔离方式,默认:采用线程隔离,ExecutionIsolationStrategy.THREAD 2 private final HystrixProperty<ExecutionIsolationStrategy> executionIsolationStrategy; 3 //使用线程隔离时,调用超时时间,默认:1秒 4 private final HystrixProperty<Integer> executionIsolationThreadTimeoutInMilliseconds; 5 //线程池的key,用于决定命令在哪个线程池执行 6 private final HystrixProperty<String> executionIsolationThreadPoolKeyOverride; 7 //使用信号量隔离时,命令调用最大的并发数,默认:10 8 private final HystrixProperty<Integer> executionIsolationSemaphoreMaxConcurrentRequests; 9 //使用信号量隔离时,命令fallback(降级)调用最大的并发数,默认:10 10 private final HystrixProperty<Integer> fallbackIsolationSemaphoreMaxConcurrentRequests; 11 //是否开启fallback降级策略 默认:true 12 private final HystrixProperty<Boolean> fallbackEnabled; 13 // 使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作.默认:true 14 private final HystrixProperty<Boolean> executionIsolationThreadInterruptOnTimeout; 15 // 统计滚动的时间窗口,默认:5000毫秒circuitBreakerSleepWindowInMilliseconds 16 private final HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds; 17 // 统计窗口的Buckets的数量,默认:10个,每秒一个Buckets统计 18 private final HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow 19 //是否开启监控统计功能,默认:true 20 private final HystrixProperty<Boolean> metricsRollingPercentileEnabled; 21 // 是否开启请求日志,默认:true 22 private final HystrixProperty<Boolean> requestLogEnabled; 23 //是否开启请求缓存,默认:true 24 private final HystrixProperty<Boolean> requestCacheEnabled; // Whether request caching is enabled.
Circuit Breaker配置源码在HystrixCommandProperties,构造Command时通过Setter进行配置,每种依赖使用一个Circuit Breaker
1 // 熔断器在整个统计时间内是否开启的阀值,默认20秒。也就是10秒钟内至少请求20次,熔断器才发挥起作用 2 private final HystrixProperty<Integer> circuitBreakerRequestVolumeThreshold; 3 //熔断器默认工作时间,默认:5秒.熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试 4 private final HystrixProperty<Integer> circuitBreakerSleepWindowInMilliseconds; 5 //是否启用熔断器,默认true. 启动 6 private final HystrixProperty<Boolean> circuitBreakerEnabled; 7 //默认:50%。当出错率超过50%后熔断器启动. 8 private final HystrixProperty<Integer> circuitBreakerErrorThresholdPercentage; 9 //是否强制开启熔断器阻断所有请求,默认:false,不开启 10 private final HystrixProperty<Boolean> circuitBreakerForceOpen; 11 //是否允许熔断器忽略错误,默认false, 不开启 12 private final HystrixProperty<Boolean> circuitBreakerForceClosed;
Command配置源码在HystrixCollapserProperties,构造Collapser时通过Setter进行配置
1 //请求合并是允许的最大请求数,默认: Integer.MAX_VALUE 2 private final HystrixProperty<Integer> maxRequestsInBatch; 3 //批处理过程中每个命令延迟的时间,默认:10毫秒 4 private final HystrixProperty<Integer> timerDelayInMilliseconds; 5 //批处理过程中是否开启请求缓存,默认:开启 6 private final HystrixProperty<Boolean> requestCacheEnabled;
1 /** 2 配置线程池大小,默认值10个. 3 建议值:请求高峰时99.5%的平均响应时间 + 向上预留一些即可 4 */ 5 HystrixThreadPoolProperties.Setter().withCoreSize(int value) 6 /** 7 配置线程值等待队列长度,默认值:-1 8 建议值:-1表示不等待直接拒绝,测试表明线程池使用直接决绝策略+ 合适大小的非回缩线程池效率最高.所以不建议修改此值。 9 当使用非回缩线程池时,queueSizeRejectionThreshold,keepAliveTimeMinutes 参数无效 10 */ 11 HystrixThreadPoolProperties.Setter().withMaxQueueSize(int value)
第四章 spring cloud hystrix 配置 2.1.4版本
原文:https://www.cnblogs.com/aizhouhui/p/10911819.html