第四章 spring cloud hystrix 配置 2.1.4版本

背景

分布式系统环境下,服务之间的依赖调动非常常见,一个业务调用通常依赖多个基础服务,如果调用某服务层,而这个服务层不可用或者因为网络等原因响应时间超出预期,请求线程被堵塞,当有大量的请求调用这个服务就会导致这个服务的资源被耗尽,无法继续对外提供服务,这也叫雪崩效应;

雪崩效应经常出现在,服务器宕机,光纤被挖断(如腾讯:https://baijiahao.baidu.com/s?id=1628812006479290058&wfr=spider&for=pc),异常流量,缓存穿透,JVM长时间FullGC,同步等待;

出现了雪崩效应,服务一个一个出问题,为了构建一个稳定可靠的分布式系统,我们的系统应该具备自我保护能力,避免雪崩效应;

服务短路(CircuitBreaker)

QPS (Query per second 每秒查询率)

QPS: 经过全链路压测,计算单机极限QPS,集群 QPS = 单机 QPS * 集群机器数量 * 可靠性比率;

全链路压测 除了压 极限QPS,还有错误数量;

全链路:一个完整的业务流程操作;

Hystrix

本文猪角Hystrix就是解决同步等待导致的雪崩问题;

对来自依赖的延迟和故障进行防护控制,一般都是通过网络调用导致的;

快速失败并迅速恢复;

停止分布式系统中的级联故障;

回退并优雅的降级;

https://github.com/Netflix/Hystrix/wiki#what-is-hystrix-for

Hystrix解决的问题

分布式系统中,各个系统错综复杂,一个系统依赖多个服务,一个服务出现问题,可能导致整个系统瘫痪;

官方文档写了,一个应用依赖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

原理图如下:

  1. 构建一个HystrixCommand或HystrixObservableCommand对象;前者逻辑在run()中,后者逻辑在construct()
  2. 执行命令

    .execute():同步阻塞方式执行run()(HystrixObservableCommand无此方法)

     .queue():异步非阻塞方式执行run()(HystrixObservableCommand无此方法)

    .observe():事件注册前调用,run()/construct(),继承HystrixCommand,hystrix创建新线程非堵塞的执行run(),后者堵塞执行construct();注册成功则执行onNext()和onCompleted,失败则执行onError();

    .toObservable():事件注册后调用,run()/construct();

  这四个方法用来触run()/construct(),一个实例也只能执行一次,并且他们都会走toObservable()

  1. 判断缓存
  2. 是否熔断
  3. 信号量/线程池是否满了
  4. 执行run()/construct();
  5. Fallback(降级)

其他不做过多介绍,如有兴趣参考https://github.com/Netflix/Hystrix/wiki/How-it-Works详细工作原理

 

spring-cloud-hystrix-client-demo

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

spring-cloud-hystrix-dashboard-demo

 主程序入口添加,@EnableHystrixDashboard

启动后,访问http://localhost:9090/hystrix

然后将/actuator/hystrix.stream 输入到页面中

然后访问fuck,返回9090程序看到图

 

配置(https://hot66hot.iteye.com/blog/2155036)

Command 配置

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.  
View Code

熔断器(Circuit Breaker)配置

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; 
View Code

命令合并(Collapser)配置

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;  
View Code

线程池(ThreadPool)配置

 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)  
View Code

 

posted @ 2019-05-23 14:46  江湖人称洗发水  阅读(911)  评论(0编辑  收藏  举报