第十节 Hystrix熔断器

亮子 2021-06-09 01:21:54 17736 0 0 0

1、什么是Hystrix?

在分布式环境中,许多服务依赖项中的一些必然会失败。Hystrix是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点、停止级联失败和提供回退选项来实现这一点,所有这些都可以提高系统的整体弹性。

图片alt

2、雪崩效应

图片alt

3、Hystrix怎么解决问题?

1)、线程隔离

线程隔离的意思是服务A调用服务B、服务C、服务D的时候,如果服务D出了问题,那么服务A之前调用服务D的线程就全都阻塞了,随着不断有新的服务A进来,服务A的web容器中的线程就会不断增加,然后不断阻塞,随后把CPU撑爆。

所以我们需要线程隔离技术把服务A和服务D的执行线程隔离开来,hystrix提供了两种线程隔离技术,分别是线程池隔离和信号量隔离。

  • 线程池隔离是指服务A调用服务D的时候,Hystrix另外搞一个新的线程池,从中取线程来执行服务D的调用,这个线程池跟服务A的web容器线程池是独立的,这样服务D的调用就不会服务A的web容器线程池。

  • 信号量隔离是指服务A调用服务D的时候,Hystrix限制服务A调用服务D的web容器线程数,比如只允许10个线程可以调用服务D,这样就算服务D挂了,服务A的web容器线程数也只有10个不能用,不影响其它线程。

线程池隔离适用于有网络延迟的RPC调用,信号量隔离适用于无网络延迟的本地调用。

2)、服务熔断

所谓服务熔断是一个整体的概念,它是说如果服务A调用服务B,服务B挂了,那么就把服务B熔断掉,以免影响服务A的运行。把服务B熔断掉,其实就是开启断路器,也就是服务降级。

服务熔断的方式有两种,分别是直接使用Hystrix的注解@HystrixCommand,和使用spring cloud 的feign组件。

3)、服务降级

服务降级的意思,就是服务在熔断之后,进入降级的方法,返回其它的结果,比如,返回一些友好的访问失败信息等。

服务降级的的时机包括如下几种:

  • 断路器已经开启状态
  • 调用请求超时
  • 调用请求执行失败,返回Exception
  • 设定的Hystrix线程池或者信号量线程数已满,且等待队列也满了

服务降级之后,会走参数fallbackMethod里面的配置的方法。如果fallbackMethod的方法也需要调用其它的微服务,那这个方法也需要加注解@HystrixCommand,避免这个降级服务也就访问挂了。

4)、断路器

断路器,英文名也circuitBreaker,就是加在服务调用之前的一套拦截器,它包括三种状态,分别是开启、关闭、半开,三种状态之间的切换时机如下:

  • 默认关闭——>开启:requestVolumeThreshold以及errorThresholdPercentage同时超出设置的阀值,就开启断路器;

  • 开启——>半开:断路器开启之后,可以通过sleepWindowInMiliseconds设置一个休眠期,默认是5秒。这5秒之内,断路器是开启状态,一旦5秒时间一到,就会暂时进入半开状态,这时候,断路器会尝试发送一个命令,看看当前请求是否还是超过上面的两个阀值。

  • 半开——>开启:如果上面半开状态下,断路器发送命令之后,发现服务还是访问失败,那么继续进入开启状态,等待下次5秒后再进入半开状态。

  • 半开——>关闭:如果上面半开状态下,断路器发送命令之后,发现服务访问OK了,也不超过那两个阀值了,那说明服务状态良好,就把断路器关了。

5)、请求缓存

服务的请求缓存,是hystrix提供一种web服务本地缓存机制,在开启Hystrix的请求缓存之后,如果同一个微服务调用请求且参数相同时,并直接通过本地缓存返回结果,不用再调用微服务。

@CacheResult加在需要本地缓存的方法上面;

@CacheRemove加在需要清除本地缓存的方法上面,通过key配置需要清除的缓存key

注意,hystrix请求缓存本质上是一个filter,所以需要再写一个Filter类初始化Hystrix的请求缓存Filter。

4、Hystrix+TestTemplate函数模式

1)、引入依赖

        <!-- hystrix -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

2)、启动类中激活hystrix

package com.mazong.serverblogarticle;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class ServerBlogArticleApplication {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ServerBlogArticleApplication.class, args);
    }

}

3)、在Controller中增加降级函数

    /**
     * 降级函数getArticle
     * @param id
     * @return
     */
    public Object fallGetArticle(Integer id) {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("fallGetArticle", "服务熔断了!!!");
        System.out.println(resultMap);

        return  resultMap;
    }

4)、接口上增加注解

    @RequestMapping(value = "/getArticle")
    @ResponseBody
    @HystrixCommand(fallbackMethod = "fallGetArticle")
    public Object getArticle(@RequestParam("id") Integer id) {
        // ... 省略
        return null;
    }

5)、运行效果

图片alt

6)、总结

配置使用的步骤:

(1)引入依赖

(2)启动类中激活

(3)配置熔断触发逻辑

(4)在需要保护的接口上使用@HystrixCommand

5、Hystrix+TestTemplate统一模式

1)、定义统一降级函数

    public Object defaultCallback() {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("fallGetArticle", "统一级别服务降级了!!!");
        System.out.println(resultMap);

        return  resultMap;
    }

注意:统一函数不能有参数。返回值要保持一致。

2)、在Controllor类上添加注解@DefaultProperties

@Controller
@RequestMapping("/")
@DefaultProperties(defaultFallback = "defaultCallback")
public class ArticleController {
    // ... 省略
}

3)、修改需要降级处理的函数

    @RequestMapping(value = "/getArticle")
    @ResponseBody
    @HystrixCommand
    public Object getArticle(@RequestParam("id") Integer id) {
        // ... 省略
    }

4)、运行效果

图片alt

参考文档: