Spring Cloud Hystrix学习笔记

Spring Cloud Hystrix主要保障服务的高可用,它提供服务隔离,以减少不同服务之间资源竞争带来的相互影响;提供服务降级;提供熔断机制使得服务可以快速失败,而不是一直阻塞等待服务响应,并能从中快速恢复。同时也可以监控服务的调用情况。

HystrixCommand的官方文档

引入依赖

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

一、服务降级

服务调用过程中,遇到超时、异常。服务熔断或线程池/信号量打满,执行另一个方法,fallback,返回提示信息。

1.1、服务方

  1. 在service方法上加上注解:
@HystrixCommand(
        // 兜底方法
        fallbackMethod = "timeoutHandle",
        commandProperties = {
                // 超时时间设置,默认1000,单位ms
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = "3000"),
                // 是否开启超时设置,默认true
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_TIMEOUT_ENABLED, value = "true"),
                // 是否开启兜底方法,默认true
                @HystrixProperty(name = HystrixPropertiesManager.FALLBACK_ENABLED, value = "true")
        }
)

其中fallbackMethod 指定处理服务降级的方法,value为最大时间,单位ms。

public String timeoutHandle() {
    return "服务繁忙,请稍后再试-";
}

注:fallback方法必须有主方法的入参。
不一定要超时,方法异常也会走fallback方法,fallback方法可以在入参里加上异常,对异常进行处理。

public String timeoutHandle(Expection e) {
    if (e != null) {
        return "方法异常";
    }
    return "服务繁忙,请稍后再试-";
}
  1. 启动类加上注解
@EnableCircuitBreaker	

1.2、消费方

  1. 在配置文件开启feign的hystrix:
feign:
  hystrix:
    enabled: true
  1. 是在controller方法上加上注解:
@HystrixCommand(
        // 兜底方法
        fallbackMethod = "timeoutHandle",
        commandProperties = {
                // 超时时间设置,默认1000,单位ms
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = "3000"),
                // 是否开启超时设置,默认true
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_TIMEOUT_ENABLED, value = "true"),
                // 是否开启兜底方法,默认true
                @HystrixProperty(name = HystrixPropertiesManager.FALLBACK_ENABLED, value = "true")
        }
)
  1. 启动类加上注解
@EnableHystrix

注意:服务方与消费方在启动类上加的开启注解不同

1.3、全局服务降级

一次性对多个做相同的服务降级处理

1.3.1、第一种方式

  1. 在类上加注解
@DefaultProperties(defaultFallback = "orderGlobalFallbackMethod")

其中orderGlobalFallbackMethod为处理服务降级的方法。

  1. 在需要按全局服务降级方法处理的方法上加上注解
@HystrixCommand

1.3.2、第二种方式

适用于feign调用的消费方

  1. 实现注解
@FeignClient

标注的接口,在实现方法时返回服务降级处理的提示

@Component
public class HystrixPaymentFeignServiceImpl implements HystrixPaymentFeignService {
    @Override
    public String timeout(int id) {
        return "系统繁忙,请稍后再试";
    }
}

注意:记得在实现类上加上@Component

  1. 在@FeignClient注解里面加上 fallback = xxx.class 指向实现类
@Component
@FeignClient(value = "HYSTRIX-PAYMENT-SERVICE", fallback = HystrixPaymentFeignServiceImpl.class)
public interface HystrixPaymentFeignService {
    /**
     * 测试feign的超时控制
     * @return 提示
     */
    @GetMapping("/payment/timeout/{id}")
    String timeout(@PathVariable("id") int id);
}

二、服务熔断

服务熔断在服务方做

原理:

默认情况下,如果统计时间达到(metrics.rollingStats.timeInMilliseconds)10,000ms,请求次数达到(circuitBreaker.requestVolumeThreshold)20次或以上,请求失败率达到或超过(circuitBreaker.errorThresholdPercentage)50%,断路器就会开启,服务熔断,拒绝请求,返回回退方法的结果,持续时间(circuitBreaker.sleepWindowInMilliseconds)5,000ms,5,000ms之后,断路器进入半开状态,尝试接收请求,如果成功,断路器关闭,如果失败,断路器开启,5,000ms之后继续尝试。

2.1、使用方法

1、在需要开启服务熔断的service方法上加上注解,其中是否使用线程池隔离,统计时间和桶的数量的设置位置不一样,使用线程池隔离的在 threadPoolProperties 里面设置

没有使用线程池隔离

@HystrixCommand(
        // 回退方法
        fallbackMethod = "paymentCircuitBreakerFallback",
        commandProperties = {
                // 是否开启断路器,默认true
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED, value = "true"),
                // 服务熔断的最小请求次数,默认20
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, value = "20"),
                // 断路器开启的请求错误率百分比,默认50,即失败率达到一半或以上
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, value = "50"),
                // 服务熔断时间,默认5000ms
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, value = "5000"),
                // 是否强制开启断路器,默认false
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_FORCE_OPEN, value = "false"),
                // 是否强制关闭断路器,默认false
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_FORCE_CLOSED, value = "false"),
                // 统计时间,默认10,000ms
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, value = "10000"),
                // 桶的数量,默认10个,用来记录请求结果状态(成功、失败、超时、拒绝),必须被统计时间整除,建议数百到数千毫秒一个桶
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_STATS_NUM_BUCKETS, value = "10"),
                // 统计结果(请求数、失败率等)刷新间隔时间,默认500ms
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_HEALTH_SNAPSHOT_INTERVAL_IN_MILLISECONDS, value = "500")
        }
)

使用线程池隔离

@HystrixCommand(
        // 回退方法
        fallbackMethod = "paymentCircuitBreakerFallback",
        commandProperties = {
        // 服务隔离设置,默认线程池隔离 THREAD,信号量 SEMAPHORE
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "THREAD"),
                // 是否开启断路器,默认true
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED, value = "true"),
                // 服务熔断的最小请求次数,默认20
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, value = "20"),
                // 断路器开启的请求错误率百分比,默认50,即失败率达到一半或以上
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, value = "50"),
                // 服务熔断时间,默认5000ms
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, value = "5000"),
                // 是否强制开启断路器,默认false
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_FORCE_OPEN, value = "false"),
                // 是否强制关闭断路器,默认false
                @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_FORCE_CLOSED, value = "false"),
                // 统计时间,默认10,000ms
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, value = "10000"),
                // 桶的数量,默认10个,用来记录请求结果状态(成功、失败、超时、拒绝),必须被统计时间整除,建议数百到数千毫秒一个桶
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_STATS_NUM_BUCKETS, value = "10"),
                // 统计结果(请求数、失败率等)刷新间隔时间,默认500ms
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_HEALTH_SNAPSHOT_INTERVAL_IN_MILLISECONDS, value = "500")
        },
//            commandKey = "order-testThread",
        // 一组hystrix命令,默认类名
//            groupKey = "order-OrderController",
        // 线程池名称,默认取(hystrix-) + (groupKey) ,即默认同一个类中使用一个线程池
//            threadPoolKey = "order-pool-1",
        threadPoolProperties = {
                // 核心线程数,默认10
                @HystrixProperty(name = HystrixPropertiesManager.CORE_SIZE, value = "10"),
                // 空闲线程最大存活时间,默认为 2,即两分钟
                @HystrixProperty(name = HystrixPropertiesManager.KEEP_ALIVE_TIME_MINUTES, value = "2"),
                // 队列的最大值,默认值为 -1
                @HystrixProperty(name = HystrixPropertiesManager.MAX_QUEUE_SIZE, value = "10"),
                // 执行拒绝策略的队列大小,默认5,所以当队列最大值大于5时,一般要设置此项
                @HystrixProperty(name = HystrixPropertiesManager.QUEUE_SIZE_REJECTION_THRESHOLD, value = "10"),
                // 统计时间,默认10,000ms
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, value = "10000"),
                // 桶的数量,默认10个,用来记录请求结果状态(成功、失败、超时、拒绝),必须被统计时间整除,建议数百到数千毫秒一个桶
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_STATS_NUM_BUCKETS, value = "10")0
        }
)

2、启动类加上注解:

@EnableCircuitBreaker

注:如果失败率达到但是“请求次数”没达到,将不会开启服务熔断机制。

2.2、学习中的问题

2.2.1、metrics.rollingStats.numBuckets存在的意义?

  1. buckets的作用:
    buckets是用来存放接口请求的结果的状态,包括成功、失败、超时、拒绝。

  2. 统计数据的实现:
    默认情况下(即10s10个桶),一个桶记录1s内接口的请求结果状态,进入下一秒后,就会新增一个桶,如果桶的数量超过10个,就会去掉最前面的一个桶,断路器是否开启的依据就是取最后10个桶的综合结果,(metrics.rollingStats.timeInMilliseconds / metrics.rollingStats.numBuckets)就是新增一个桶的间隔时间,所以这个值必须是整数。

三、服务监控

3.1、创建监控服务

  1. 创建项目;
  2. 引入依赖;
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
 </dependency>
  1. 配置监控参数

在需要监控的接口上加上注解

@HystrixCommand(
        commandProperties = {
                // 是否开启百分位的统计,默认true
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_PERCENTILE_ENABLED, value = "true"),
                // 百分位统计时间区间,默认60,000ms
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_PERCENTILE_TIME_IN_MILLISECONDS, value = "60000"),
                // 百分位统计的桶的数量,默认6个,桶的数量必须能被统计时间整除
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_PERCENTILE_NUM_BUCKETS, value = "6"),
                // 每个桶统计的请求最大个数,默认100个,超过就取最后的
                @HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_PERCENTILE_BUCKET_SIZE, value = "100")
        }
)
  1. 开启监控
    在启动类加上注解
@EnableHystrixDashboard
  1. 访问页面:http://localhost:9001/hystrix

在这里插入图片描述

监控路径为需要监控的服务IP和端口加上/hystrix.stream
http://localhost:8001/hystrix.stream

在这里插入图片描述

3.2、问题解决

  1. 如果报错Unable to connect to Command Metric Stream.在需要监控的服务启动类加上:
@Bean
public ServletRegistrationBean<HystrixMetricsStreamServlet> getServlet() {
    HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
    ServletRegistrationBean<HystrixMetricsStreamServlet> registrationBean = new ServletRegistrationBean<>(streamServlet);
    registrationBean.setLoadOnStartup(1);
    registrationBean.addUrlMappings("/hystrix.stream");
    registrationBean.setName("HystrixMetricsStreamServlet");
    return registrationBean;
}

其中registrationBean.addUrlMappings("/hystrix.stream");为指定监控路径。
2. 需要监控的服务是否有引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

四、服务隔离(限流)

Tomcat默认只有一个线程池,所有http请求共享,当服务中部分接口响应过慢,导致请求一直占用线程,最后请求堆积到占满这个线程池,就没有线程可以接收新的请求,致使服务中其他接口也无法访问,最终导致整个服务不可用,这就是服务的雪崩效应,服务隔离就是为了防止服务的雪崩,保护服务。

缺点:增加CPU和内存开销

Hystrix的服务隔离策略有两种,分别为:线程池隔离和信号量隔离。

4.1、线程池隔离

  1. 引入依赖;
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  1. 在方法上加上注解;
@HystrixCommand(
        commandProperties = {
                // 服务隔离设置,默认线程池隔离 THREAD,信号量 SEMAPHORE
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "THREAD"),
                // 线程隔离中超时是否中断执行,默认true
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_INTERRUPT_ON_TIMEOUT, value = "true"),
                // 同时有多少个线程可以调用兜底方法,默认10,超出就会报错,在服务隔离时设置使用
                @HystrixProperty(name = HystrixPropertiesManager.FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = "10")
        },
//            commandKey = "order-testThread",
        // 一组hystrix命令,默认类名
//            groupKey = "order-OrderController",
        // 线程池名称,默认取(hystrix-) + (groupKey) ,即默认同一个类中使用一个线程池
//            threadPoolKey = "order-pool-1",
        threadPoolProperties = {
                // 核心线程数,默认10
                @HystrixProperty(name = HystrixPropertiesManager.CORE_SIZE, value = "10"),
                // 空闲线程最大存活时间,默认为 2,即两分钟
                @HystrixProperty(name = HystrixPropertiesManager.KEEP_ALIVE_TIME_MINUTES, value = "2"),
                // 队列的最大值,默认值为 -1
                @HystrixProperty(name = HystrixPropertiesManager.MAX_QUEUE_SIZE, value = "10"),
                // 执行拒绝策略的队列大小,默认5,所以当队列最大值大于5时,一般要设置此项
                @HystrixProperty(name = HystrixPropertiesManager.QUEUE_SIZE_REJECTION_THRESHOLD, value = "10")
        },
        // 异常情况的兜底方法
        fallbackMethod = "fallbackMethod"
)
  1. 在启动类上加上注解开启hystrix;
@EnableHystrix

4.2、信号量隔离

就是对接口进行限流,只是增加了一个计数器,计算接口占用的请求线程数量是否达到最大值,每一次请求计数器加一,每一次响应计数器减一。

  1. 引入依赖;
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  1. 在方法上加上注解;
@HystrixCommand(
        // 兜底方法
        fallbackMethod = "fallbackMethod",
        commandProperties = {
                // 服务隔离设置,默认线程池隔离 THREAD,信号量 SEMAPHORE
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE"),
                // 最大并发请求数,即信号量的大小,默认10
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = "10"),
                // 同时有多少个线程可以调用兜底方法,默认10,超出就会报错,在服务隔离时设置使用
                @HystrixProperty(name = HystrixPropertiesManager.FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = "10")
        }
)
  1. 在启动类上加上注解开启hystrix;
@EnableHystrix

4.3、两种隔离的区别

区别项线程池隔离信号量隔离
是否创建线程池
是否支持排队
增加的开销大小
从接口耗时方面适合使用的场景
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值