SpringCloud实战之路 | 应用篇(三)服务熔断器Hystrix工作流程及高级应用

SpringCloud实战之路 | 应用篇(三)服务熔断器Hystrix工作流程及高级应用

文章内容输出来源:拉勾教育Java高薪训练营;

Hystrix介绍

Hystrix,宣言“defend your app”是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。Hystrix主要通过以下几点实现延迟和容错。

  • 包裹请求:使用HystrixCommand包裹对依赖的调⽤逻辑。 自动投递微服务方法(@HystrixCommand 添加Hystrix控制)
  • 跳闸机制:当某服务的错误率超过一定的阈值时,Hystrix可以跳闸,停止请求该服务一段时间。
  • 资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(舱壁模式)(或者信号量)。如果该线程池已满, - 发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。
  • 监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等。
  • 回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑由开发人员自行提供,例如返回一个缺省值。
  • 自我修复:断路器打开一段时间后,会自动进入“半开”状态

在这里插入图片描述

具体实现

引入maven依赖坐标

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

启动类添加熔断器开启注解@EnableCircuitBreaker

@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现
@EnableCircuitBreaker // 开启熔断
public class Application {
	 public static void main(String[] args) {
	 	SpringApplication.run(Application .class, args);
	 }
	 /**
	 * 注⼊RestTemplate
	 * @return
	 */
	 @Bean
	 // Ribbon负载均衡
	 @LoadBalanced
	 public RestTemplate getRestTemplate() {
	 	return new RestTemplate();
	 }
}

定义服务降级处理方法,并在业务方法上使用@HystrixCommand的fallbackMethod属性关联到
服务降级处理方法

@RestController
@RequestMapping("/test")
public class TestController {


    @Autowired
    private RestTemplate restTemplate;

	@GetMapping("/test/{id}")
    @HystrixCommand(
            // 线程池标识,要保持唯一,不唯一的话就共用了
            threadPoolKey = "findResumeOpenStateTimeoutFallback",
            // 线程池细节属性配置
            threadPoolProperties = {
                    @HystrixProperty(name="coreSize",value = "2"), // 线程数
                    @HystrixProperty(name="maxQueueSize",value="20") // 等待队列长度
            },
            // commandProperties熔断的一些细节属性配置
            commandProperties = {
                    // 每一个属性都是一个HystrixProperty                   @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
                    // hystrix高级配置,定制工作过程细节
                    ,
                    // 统计时间窗口定义
                    @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "8000"),
                    // 统计时间窗口内的最小请求数
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "2"),
                    // 统计时间窗口内的错误数量百分比阈值
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
                    // 自我修复时的活动窗口长度
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "3000")



            },
            fallbackMethod = "myFallBack"  // 回退方法
    )
    public Integer test(@PathVariable Long id) {
        // 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
        String url = "http://server/test/" + id;  // 指定服务名
        Integer forObject = restTemplate.getForObject(url, Integer.class);
        return forObject;
    }


    /*
        定义回退方法,返回预设默认值
        注意:该方法形参和返回值与原始方法保持一致
     */
    public Integer myFallBack(Long id) {
        return -123333; // 兜底数据
    }
}

注意
降级(兜底)方法必须和被降级方法相同的方法签名(相同参数列表、相同返回值)

测试
当请求超时时候返回直接返回降级方法结果

结果:
-123333

Hystrix工作流程

 Hystrix工作流程

  1. 在调用出现问题时,会开启一个时间窗(默认为10s)
  2. 在这个时间窗内,统计请求次数是否达到了最小的请求数
    如果未达到最小的请求数,则重置统计信息回到第一步(因为在请求数过少的情况下,有可能是偶尔出现的调用问题,后面就不会采取跳闸,或者切断的措施,要达到一定数量的统计才有意义)
    如果达到最小的请求数,则统计请求失败的数量占所有请求数量的百分比是否达到阈值,
    如果未达到阈值则重置统计信息回到第一步(原因同最小请求数)
    如果达到阈值,跳闸(不在请求对应服务)
  3. 如果跳闸,会打开一个新的活动窗口(默认5s),会每隔5s,Hystrix放行一个请求,到达问题服务,看是否调用成功,如果成功,则认为该服务恢复正常,重置断路器回到第1步,如果失败,回到第3步。

其中的参数通过配置可以定制修改

  • execution.isolation.thread.timeoutInMilliseconds: 降级处理超时时间
  • metrics.rollingStats.timeInMilliseconds : 统计时间窗口定义
  • circuitBreaker.requestVolumeThreshold : 统计时间窗口内的最小请求数
  • circuitBreaker.errorThresholdPercentage: 统计时间窗口内的错误数量百分比阈值
  • circuitBreaker.sleepWindowInMilliseconds: 自我修复时的活动窗口长度
	@GetMapping("/test/{id}")
    @HystrixCommand(
            // commandProperties熔断的一些细节属性配置
            commandProperties = {
                    // 每一个属性都是一个HystrixProperty
                    //降级处理超时时间
                    @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000"),

                    // hystrix高级配置,定制工作过程细节
                    
                    // 统计时间窗口定义
                    @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "8000"),
                    // 统计时间窗口内的最小请求数
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "2"),
                    // 统计时间窗口内的错误数量百分比阈值
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
                    // 自我修复时的活动窗口长度
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "3000")

            },
            fallbackMethod = "myFallBack"  // 回退方法
    )
    public Integer test(@PathVariable Long id) {
        // 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
        String url = "http://server/test/" + id;  // 指定服务名
        Integer forObject = restTemplate.getForObject(url, Integer.class);
        return forObject;
    }
    
	/*
     *  定义回退方法,返回预设默认值
     *  注意:该方法形参和返回值与原始方法保持一致
     */
    public Integer myFallBack(Long userId) {
        return -1; // 兜底数据
    }

Hystrix舱壁模式(线程池隔离策略)

默认情况下,Hystrix有一个线程池(10个),所有加了@HystrixCommand注解的方法共用这一个线程池,如果这些方法接受的请求超过了10个,其他请求就会等待或者拒绝连接。
在这里插入图片描述
如果不进行设置,所有熔断方法将会公用一个Hystrix线程池(10个线程),如果方法1有把10个线程都占用了,方法2请求处理时不会去访问B服务,因为无线程可用。

为了处理由于请求过多而导致服务无法访问,hystrix不是采用增加线程数,而是可以为每一个方法单独开启一个线程池,这种模式叫做舱壁模式,也是线程隔离的⼿段。
在这里插入图片描述
配置方式:

	@HystrixCommand(
            // 线程池标识,要保持唯一,不唯一的话就共用了
            threadPoolKey = "test",
            // 线程池细节属性配置
            threadPoolProperties = {
                    @HystrixProperty(name="coreSize",value = "1"), // 线程数
                    @HystrixProperty(name="maxQueueSize",value="20") // 等待队列长度
            },
            // commandProperties熔断的一些细节属性配置
            commandProperties = {
                    // 每一个属性都是一个HystrixProperty
                    //降级处理超时时间
                    @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
            }
    )
    @GetMapping("/test/{id}")
    public Integer test(@PathVariable Long id) {
        // 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
        String url = "http://server/test/" + id;  // 指定服务名
        Integer forObject = restTemplate.getForObject(url, Integer.class);
        return forObject;
    }

猜你喜欢

转载自blog.csdn.net/qq_23830637/article/details/105755658
今日推荐