服务间的隔离及断路器-Hystrix - 图1
服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心
任务的正常运行。
Hystrix主要是为了解决服务雪崩问题:

  1. 降级机制:当你的某一个服务出现超时时,资源不足,出现了异常,可以执行一个降级方法,返回一个托底数据
  2. 隔离:提供了一个Hystrix线程池,信号量,和tomcat的线程池相互隔离。
  3. 熔断:当你的某一个服务的失败率达到一定的阈值时,自动触发降级
  4. 缓存:请求缓存的功能

    1、降级机制实现

导入依赖 customer

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  4. </dependency>

添加一个注解(启动类)

  1. @EnableCircuitBreaker

针对某一个接口去编写他的降级方法

  1. @GetMapping("/customer/{id}")
  2. @HystrixCommand(fallbackMethod = "findByIdFallBack")
  3. public Customer findById(@PathVariable Integer id){
  4. int i = 1/0;
  5. return searchClient.findById(id);
  6. }
  7. // findById的降级方法 方法的描述要和接口一致
  8. public Customer findByIdFallBack(Integer id){
  9. return new Customer(-1,"",0);
  10. }

在接口上添加注解

  1. @HystrixCommand(fallbackMethod = "findByIdFallBack")

2、线程隔离

如果使用Tomcat的线程池去接收用户的请求,使用当前线程去执行其他服务的功能,如果某一个服务出现了故障,导致tomcat的线程大量的堆积,导致Tomcat无法处理其他业务功能。

  • Hystrix的线程池(只要加上注解hystrixcommand默认),接收用户请求采用tomcat的线程池,执行业务代码,调用其他服务时,采用Hystrix的线程池。
  • 信号量,使用的还是Tomcat的线程池,帮助我们去管理Tomcat的线程池。

Hystrix的线程池的配置

配置信息 name value
线程隔离策略 execution.isolation.strateg THREAD 线程池
指定超时时间 execution.isolation.thread.timeoutInMilliseconds 1000
是否开启超时时间配置 execution.timeout.enabled true
超时之后是否中断线程 execution.isolation.thread.interruptOnTimeout true
取消任务后知否 execution.isolation.thread.interruptOnCancel false

代码实现

  1. @GetMapping("/customer/{id}")
  2. @HystrixCommand(fallbackMethod = "findByIdFallBack",commandProperties = {
  3. @HystrixProperty(name = "execution.isolation.strategy",value = "THREAD"),
  4. @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
  5. })
  6. public Customer findById(@PathVariable Integer id) throws InterruptedException {
  7. System.out.println(Thread.currentThread().getName());
  8. Thread.sleep(300);
  9. return searchClient.findById(id);
  10. }

信号量的配置信息

  1. @GetMapping("/customer/{id}")
  2. @HystrixCommand(fallbackMethod = "findByIdFallBack",commandProperties = {
  3. @HystrixProperty(name = "execution.isolation.strategy",value = "SEMAPHORE")
  4. })
  5. public Customer findById(@PathVariable Integer id) throws InterruptedException {
  6. System.out.println(Thread.currentThread().getName());
  7. return searchClient.findById(id);
  8. }

3、断路器

3.1 断路器介绍

马丁福勒断路器论文:https://martinfowler.com/bliki/CircuitBreaker.html
在调用指定服务时,如果说这个服务的失败率达到你输入的一个阈值,将断路器从closed状态,转变为open状态,指定服务时无法被访问的,如果你访问就直接走fallback方法,在一定的时间内,open状态会再次转变为half open状态,允许一个请求发送到我的指定服务,如果成功,转变为closed,如果失败,服务再次转变为open状态,会再次循环到half open,直到断路器回到一个closed状态。服务间的隔离及断路器-Hystrix - 图2

3.2 配置断路器的监控界面

导入依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
  4. </dependency>

在启动类中添加注解

  1. @EnableHystrixDashboard

配置一个Servlet路径,指定上Hystrix的Servlet

  1. @WebServlet("/hystrix.stream")
  2. public class HystrixServlet extends HystrixMetricsStreamServlet {
  3. }
  4. //------------------------------------------------------------
  5. // 在启动类上,添加扫描Servlet的注解
  6. @ServletComponentScan("com.qf.servlet")

添加yml文件配置

  1. hystrix:
  2. dashboard:
  3. proxy-stream-allow-list: "localhost"

测试直接访问http://host:port/hystrix
服务间的隔离及断路器-Hystrix - 图3
在当前位置输入映射好的servlet路径

3.3 配置断路器的属性

断路器的属性(默认10s秒中之内请求数)

配置信息 name value
断路器的开关 circuitBreaker.enabled true
失败阈值的总请求数 circuitBreaker.requestVolumeThreshold 20
请求总数失败率达到%多少时 circuitBreaker.errorThresholdPercentage 50
断路器open状态后,多少秒是拒绝请求的 circuitBreaker.sleepWindowInMilliseconds 5000
强制让服务拒绝请求 circuitBreaker.forceOpen false
强制让服务接收请求 circuitBreaker.forceClosed false

具体配置方式

  1. @GetMapping("/customer/{id}")
  2. @HystrixCommand(fallbackMethod = "findByIdFallBack",commandProperties = {
  3. @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),
  4. @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),
  5. @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "70"),
  6. @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000")
  7. })

4 请求缓存

4.1 请求缓存介绍 相当于我们的学习的mybatis session 缓存
  • 请求缓存的声明周期是一次请求
  • 请求缓存是缓存当前线程中的一个方法,将方法参数作为key,方法的返回结果作为value
  • 在一次请求中,目标方法被调用过一次,以后就都会被缓存。

服务间的隔离及断路器-Hystrix - 图4

4.2 请求缓存的实现

创建一个Service,在Service中调用Search服务。

  1. @Service
  2. public class CustomerService {
  3. @Autowired
  4. private SearchClient searchClient;
  5. @CacheResult
  6. @HystrixCommand(commandKey = "findById")
  7. public Customer findById(@CacheKey Integer id) throws InterruptedException {
  8. return searchClient.findById(id);
  9. }
  10. @CacheRemove(commandKey = "findById")
  11. @HystrixCommand
  12. public void clearFindById(@CacheKey Integer id){
  13. System.out.println("findById被清空");
  14. }
  15. }

使用请求缓存的注解
@CacheResult:帮助我们缓存当前方法的返回结果(必须@HystrixCommand配合使用)
@CacheRemove:帮助我们清楚某一个缓存信息(基于commandKey)
@CacheKey:指定哪个方法参数作为缓存的标识

编写Filter,去构建HystrixRequestContext

  1. @WebFilter("/*")
  2. public class HystrixRequestContextInitFilter implements Filter {
  3. @Override
  4. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  5. HystrixRequestContext.initializeContext();
  6. filterChain.doFilter(servletRequest,servletResponse);
  7. }
  8. }

修改Controller

  1. public Customer findById(@PathVariable Integer id) throws InterruptedException {
  2. System.out.println(customerService.findById(id));
  3. System.out.println(customerService.findById(id));
  4. customerService.clearFindById(id);
  5. System.out.println(customerService.findById(id));
  6. System.out.println(customerService.findById(id));
  7. return searchClient.findById(id);
  8. }