【SpringCloud】SpringCloud Hystrix详解

前言

微服务中,A调用B,B调C,C调D等等,然后最后那个调用服务出问题了,那么请求都会堆积到订单服务,然后最后可能会导致整个项目不可用,这被称为服务雪崩,那我们怎么解决呢?
Spring Cloud最新面试题
Spring Cloud Nacos详解之注册中心
Spring Cloud Nacos详解之配置中心
Spring Cloud Nacos详解之集群配置
Spring Cloud Eureka详解
Spring Cloud Frign详解
Spring Cloud Ribbon详解
Spring Cloud Gateway详解

SpringCloud Hystrix

一.什么会导致服务雪崩呢

1.服务提供者不可用: 硬件故障、程序bug、缓存击穿、并发请求量过大等。
2.服务消费者不可用: 同步请求阻塞造成的资源耗尽等。
3.重试加大流量: 用户重试、代码重试等。

二.降级和熔断以及区别

服务降级: 当出现请求超时、资源不足时(线程或者信号量),会进行服务降级,就是去返回fallback方法的结果。
服务熔断: 当失败率(网络故障或者超时造成)达到阈值自动触发降级,是一种特殊的降级。

区别: 降级每个请求都会发送过去,而熔断不一定,达到失败率,请求就不会再去发送了。请求出错时熔断返回的是fallback数据,而熔断则是一段时间不会去访问服务提供者。
比如: ①降级:A调B,发送10个请求,即使每个请求都超时,也会去请求B。
     ②熔断:A调B,发送10个请求,失败率设置为50%,如果5个请求失败,此时失败率到了50%,那么后面的5个请求就不会走到B。

三.如何防止服务雪崩

1.服务降级
2.服务熔断

3.服务隔离: 分为线程池隔离和信号量隔离。通过判断线程池和信号量是否已满,超出的请求进行服务降级,从而达到限流的作用。
4.请求合并: 把一段时间内的请求合并成一个。
5.请求缓存: A调B,然后再A添加缓存,之后都从缓存中取,不用去访问B了。使用 Spring Cache实现。
注意: 因为都是服务消费者调用服务提供者出现的错误,所以处理雪崩都是在 服务消费者(A调B,A就是消费者) 中配置。


四.服务降级实践

1.pom文件引入依赖

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

2.启动类添加注解

@EnableCircuitBreaker

3.实现降级

注意:fallbackMethod接口的参数、返回值一定和调用的方法一样,不然会报错。

	@HystrixCommand(
		fallbackMethod = "timeoutError", //服务降级走的方法
		commandProperties = {
    
     //请求此方法超过三秒就会进行服务降级操作
        	@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    @GetMapping("{orderId}")
    public String queryOrderByUserId(@PathVariable("orderId") Long orderId) throws InterruptedException {
    
    
        //睡眠4秒。假设远程调用接口不通
        TimeUnit.SECONDS.sleep(4000);
        return "我是真爱粉";
    }
	
	/**
	* 服务降级走的方法
	**/
    public String timeoutError(@PathVariable("orderId") Long orderId) {
    
    
        return "你是小黑子";
    }

在这里插入图片描述

五.服务熔断实践

1.服务熔断步骤

1.当调用出现错误时,开启一个时间窗 (默认10秒)。
2.在这个时间窗内,统计调用次数是否达到最小请求数?
    (1) 没有达到,则重置统计信息,回到第1步(认为服务没有问题)。
    (2) 达到了,则统计 失败的请求数 占所有请求数的百分比,是否达到阈值?
        ①达到阈值,跳闸(不再请求对应服务,熔断开启)。
        ②没达到阈值,则重置统计信息,回到第1步(认为服务没有问题)。
3.如果跳闸,开启一个活动窗口(默认5秒),每隔5秒,Hystrix会让一个请求通过,去请求出问题的服务,看是否能调通。
    (1) 调通,重置断路器,回到第1步(认为服务没有问题)。
    (2) 调不通,回到第3步。

在这里插入图片描述

2.实现熔断

    //5秒之内,请求数达到3,并且失败率为30%,就跳闸。(在你需要调用其他方法的方法上加)
	@HystrixCommand(
		fallbackMethod = "timeoutError", //服务降级走的方法
        threadPoolProperties = {
    
    
        	 //调用的接口出现问题,时间窗口设置为5秒
             @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "5000"), 
             
             //最小请求数为3
             @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "3"),
             
             //判断是否达到阈值,即请求的失败率是30
             @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "30")
             
			//活动窗口为2秒,熔断之后,2秒内不去请求远程服务
			@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "2000")
        }
     )
     @GetMapping("{orderId}")
    public String queryOrderByUserId(@PathVariable("orderId") Long orderId) throws InterruptedException {
    
    
        	//远程调用用户服务
        	return "我是ikun"
     }

	/**
	* 服务降级走的方法
	**/
    public String timeoutError(@PathVariable("orderId") Long orderId) {
    
    
        return "你是小黑子";
    }

六.服务隔离实践(线程池隔离)

1.为什么要使用线程池隔离?
在这里插入图片描述

2.线程池隔离(舱壁模式)
在这里插入图片描述
3.线程池隔离的优缺点

优点:
(1) 即使自己线程池满了,也不会影响其他服务。
(2) 每个都有独立线程。一定程度上解决了高并发问题。
(3) 由于线程池的线程有限制,所以一定程度上解决了限流问题。

缺点:
(1) 增加CPU的开销,因为不光有tomcat线程池还有Hystrix线程池。

4.实现线程池隔离

注意:不配置线程池隔离,是tomcat管理线程,配置之后是Hystrix管理线程。

	@HystrixCommand(
		groupKey = "ikun",//在同一组的共用一个线程池(一般用于同一个服务、同一个功能的CRUD等)
		commandKey = "queryOrderByUserId", //可以自定义,一般是当前方法名
		threadPoolKey = "ikun",//唯一线程池名称,所以默认和 groupKey 名称一样 
        threadPoolProperties = {
    
    
             @HystrixProperty(name="coreSize",value="5"), //线程池大小为5
             @HystrixProperty(name="maxQueueSize",value="2") //阻塞队列最大为250
        }
	)
    @GetMapping("{orderId}")
    public String queryOrderByUserId(@PathVariable("orderId") Long orderId) throws InterruptedException {
    
    
        // 返回当前线程名称
        return Thread.currentThread().getName();
    }

没配置线程池隔离(tomcat管理线程)
在这里插入图片描述

配置线程池隔离(Hystrix管理线程)
在这里插入图片描述

七.服务隔离实践(信号量隔离)

1.信号量是什么?

  java.util.concurrent.Semaphore用来控制同时并发的线程数。通过构造方法决定线程执行数量,每次执行线程会去acquire() 方法获取许可,然后执行完通过 release() 方法释放许可,如果们没有许可用,那就线程阻塞,等待其他线程释放许可。
  信号量隔离技术:设置信号量初始值,信号量相当对关卡,每个线程通过关卡,信号量 -1,直到为 0,不允许线程通过,然后执行fallback(),进行限流。(简单来说就是一个计数器)

2.实现信号量隔离

 @HystrixCommand(
            commandProperties = {
    
    
            		//开启信号量隔离模式     THREAD:线程池隔离(默认),   SEMAPHORE:信号量隔离
                    @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY,value = "SEMAPHORE"),
                    //信号量隔离最大并发数为5,超过5个请求会走服务降级方法
                    @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS,value = "5"),
                    //服务降级并发量最大为3,超过3个请求会阻塞
                    @HystrixProperty(name = HystrixPropertiesManager.FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS,value = "3"),
            },
            
            //服务降级方法
            fallbackMethod = "timeoutError" 
    )
    @GetMapping("{orderId}")
    public String queryOrderByUserId(@PathVariable("orderId") Long orderId) throws InterruptedException {
    
    
        // 调用用户服务逻辑
        return "我是ikun";
    }

	/**
	* 降级方法
	**/
    public String timeoutError(@PathVariable("orderId") Long orderId) {
    
    
        return "你是小黑子";
    }

八.请求合并实践

1.什么情况需要请求合并

高并发下需要请求合并,因为tomcat并发量大约在600,多出的请求都会进行等待,导致响应延迟。

2.请求合并的缺点

如果我们需要把20ms内的请求合并起来,本来一个请求1ms就执行完,但是这个请求现在还需要等待19ms,才能执行,增加了耗时。但是如果是一个高延迟命令,那么就可以请求合并。

3.请求合并的参数

参数 作用 注意事项
@HystrixCollapser 请求合并注解 @HystrixCollapser标注的方法,返回值类型必须是 Future (使用异步方法,进行请求合并)。
batchMethod 合并请求的方法 方法只能接收一个参数,如果需要多个参数,那就封装成一个类参数。
scope 请求方式(默认REQUEST) REQUEST:对一个request请求内的多次服务请求进行合并。GLOBAL:多个单个应用中的所有线程的请求中的多次服务请求进行合并。
timerDelayInMilliseconds 合并请求的时间(默认10ms) 建议尽量时间不要太大
maxRequestsInBatch 最大合并请求数(Integer.MAX.VAULE)

4.实现请求合并

注意:

	@HystrixCollapser(
		//请求合并走的方法
		batchMethod = "hebing", 
		//开启GLOBAL模式
		scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL
        collapserProperties = {
    
    
        	 //合并10ms内的请求
             @HystrixProperty(name = "timerDelayInMilliseconds",value = "10"), 
             
             //最多合并250个请求
             @HystrixProperty(name = "maxRequestsInBatch",value = "250"),
        }
     )
     //这个方法因为被请求合并了,所以恒不被执行,他的请求都被 hebing() 这个方法接收执行了
     @GetMapping("{orderId}")
    public Future<Long> queryOrderByUserId(@PathVariable("orderId") Long orderId) throws InterruptedException {
    
    
    		
        	//远程调用服务
        	return "ok"
     }

	/**
	* 合并请求的方法
	* 为啥返回值List呢,因为多个请求的返回值放在一起了,
	* List(0)是第一个请求的返回值,依次类推。所以传的参数也是一个道理。
	**/
	@HystrixCommand
    public List<Long> hebing(@PathVariable("orderId") List<Long> orderIds) {
    
    
    	List list = 调用远程服务(远程服务方法返回值是Long类型)
        return list;
    }

	/**
	*10ms调用两次,然后会请求合并,因为你10ms之内,你就算单身50年,你也点不出来第二下
	**/
    public List<Long> moni(@PathVariable("orderId") List<Long> orderIds) {
    
    
    	//调用两次 queryOrderByUserId() 方法
        return "调用成功";
    }

九.Hystrix-dashboard(健康状态监控)

注意:只监测和Hystrix相关的接口。

Hystr-dashboard能够让 Actuator(SpringBoot的监控器:返回是json,观看不便) 转为界面视图。

1.pom文件添加依赖

		<!--Hystrix-dashboard依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <!--springboot actuator依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2.配置yml文件

management:
  endpoint:
    web:
      exposure:
        include: hystrix.stream

3.启动类配置注解

@EnableHystrixDashboard

4.启动项目 http://ip+端口/hystrix

在这里插入图片描述

注意: 需要对你监测的服务,随便访问几个接口,就能监测到。
在这里插入图片描述

十.Hystrix-dashboard错误解决

1 hystrix.stream 404导致监测不到信息

在这里插入图片描述
在这里插入图片描述

解决: 启动类里编写(springboot2.0以上才需要编写)

//springboot2.0以上版本,使用hystrix的dashboard要配置一个servlet
    @Bean
    public ServletRegistrationBean getServlet() {
    
    
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }

重新尝试访问监视路径:http://ip+端口/actuator/hystrix.streamhttp://ip+端口/hystrix.stream 页面如下就对了。
在这里插入图片描述

2.不在允许的代理主机名列表中

在这里插入图片描述
在这里插入图片描述
在yml文件添加,重新访问 http://ip+端口/hystrix

//添加允许访问列表
hystrix:
  dashboard:
    proxy-stream-allow-list: "*"

猜你喜欢

转载自blog.csdn.net/twotwo22222/article/details/129430058