天天看点

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

本系列博文为学习资料,是根据老师讲义,加上自己理解描述整理而成。如有不当之处希望不吝指正,持续更新改正。

服务雪崩

雪崩是系统中的蝴蝶效应导致其发生的原因多种多样,有不合理的容量设计,或者是高并发 下某一个方法响应变慢,亦或是某台机器的资源耗尽。从源头上我们无法完全杜绝雪崩源头 的发生,但是雪崩的根本原因来源于服务之间的强依赖,所以我们可以提前评估。当整个微 服务系统中,有一个节点出现异常情况,就有可能在高并发的情况下出现雪崩,导致调用它 的上游系统出现响应延迟,响应延迟就会导致 tomcat 连接本耗尽,导致该服务节点不能正 常的接收到正常的情况,这就是服务雪崩行为。

这里直接附上老师的例子:

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断
架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

服务隔离

如果整个系统雪崩是由于一个接口导致的,由于这一个接口响应不及时导致问题,那么我们 就有必要对这个接口进行隔离,就是只允许这个接口最多能接受多少的并发,做了这样的限 制后,该接口的主机就会空余线程出来接收其他的情况,不会被哪个坏了的接口占用满。 Hystrix 就是一个不错的服务隔离框架。

Hystrix 的导入

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

启动类开启 hystrix 功能

import com.xiangxue.jack.service.feign.StudentService;
import com.xiangxue.jack.service.feign.TeacherServiceFeign;
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.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication(scanBasePackages = {"com.xiangxue.jack"})
//注册到eureka
@EnableEurekaClient
//开启断路器功能
@EnableCircuitBreaker
//开启feign支持,clients指定哪个类开启feign
@EnableFeignClients(clients = {StudentService.class,TeacherServiceFeign.class})
//开启重试功能
@EnableRetry
public class MicroWebApplication {

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
//        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
//        factory.setConnectionRequestTimeout(2000);
//        factory.setReadTimeout(4000);
        return new RestTemplate();
    }

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

           

代码使用:

@HystrixCommand
    @Override
    public String queryTicket() {
        return "queryTicket1";
    }
           

Hystrix 服务隔离策略

1、线程池隔离

THREAD 线程池隔离策略 独立线程接收请求 默认的

默认采用的就是线程池隔离

代码配置

/**
     * Command属性
     * execution.isolation.strategy  执行的隔离策略
     * THREAD 线程池隔离策略  独立线程接收请求
     * SEMAPHORE 信号量隔离策略 在调用线程上执行
     * <p>
     * execution.isolation.thread.timeoutInMilliseconds  设置HystrixCommand执行的超时时间,单位毫秒
     * execution.timeout.enabled  是否启动超时时间,true,false
     * execution.isolation.semaphore.maxConcurrentRequests  隔离策略为信号量的时候,该属性来配置信号量的大小,最大并发达到信号量时,后续请求被拒绝
     * <p>
     * circuitBreaker.enabled   是否开启断路器功能
     * circuitBreaker.requestVolumeThreshold  该属性设置在滚动时间窗口中,断路器的最小请求数。默认20,如果在窗口时间内请求次数19,即使19个全部失败,断路器也不会打开
     * circuitBreaker.sleepWindowInMilliseconds    改属性用来设置当断路器打开之后的休眠时间,休眠时间结束后断路器为半开状态,断路器能接受请求,如果请求失败又重新回到打开状态,如果请求成功又回到关闭状态
     * circuitBreaker.errorThresholdPercentage  该属性设置断路器打开的错误百分比。在滚动时间内,在请求数量超过circuitBreaker.requestVolumeThreshold,如果错误请求数的百分比超过这个比例,断路器就为打开状态
     * circuitBreaker.forceOpen   true表示强制打开断路器,拒绝所有请求
     * circuitBreaker.forceClosed  true表示强制进入关闭状态,接收所有请求
     * <p>
     * metrics.rollingStats.timeInMilliseconds   设置滚动时间窗的长度,单位毫秒。这个时间窗口就是断路器收集信息的持续时间。断路器在收集指标信息的时会根据这个时间窗口把这个窗口拆分成多个桶,每个桶代表一段时间的指标,默认10000
     * metrics.rollingStats.numBuckets   滚动时间窗统计指标信息划分的桶的数量,但是滚动时间必须能够整除这个桶的个数,要不然抛异常
     * <p>
     * requestCache.enabled   是否开启请求缓存,默认为true
     * requestLog.enabled 是否打印日志到HystrixRequestLog中,默认true
     *
     * @HystrixCollapser 请求合并
     * maxRequestsInBatch  设置一次请求合并批处理中允许的最大请求数
     * timerDelayInMilliseconds  设置批处理过程中每个命令延迟时间
     * requestCache.enabled   批处理过程中是否开启请求缓存,默认true
     * <p>
     * threadPoolProperties
     * threadPoolProperties 属性
     * coreSize   执行命令线程池的最大线程数,也就是命令执行的最大并发数,默认10
     */
    @HystrixCommand(fallbackMethod = "queryContentsFallback",
            commandKey = "queryContents",
            groupKey = "querygroup-one",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests",value = "100"),
                    @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"),
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000000000")
            },
            threadPoolKey = "queryContentshystrixJackpool", threadPoolProperties = {
//            @HystrixProperty(name = "coreSize", value = "100")
    })

           

默认线程池中有 10 个线程,可以配置线程池中线程大小

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

线程池隔离策略,hystrix 是会单独创建线程的,单元测试如下:

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断
架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

可以看到,用户线程和业务类中的线程是不一样的

2、信号量隔离

信号量隔离是采用一个全局变量来控制并发量,一个请求过来全局变量加 1,单加到跟配置 中的大小相等是就不再接受用户请求了。

代码配置

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

execution.isolation.semaphore.maxConcurrentRequests 这参数是用来控制信号量隔离级别的并发大小的。

单元测试

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断
架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

可以看到,单元测试中的线程和业务类中的线程是一样的,没有单独开启线程。

Hystrix 服务降级

服务降级是对服务调用过程的出现的异常的友好封装,当出现异常时,我们不希 望直接把异常原样返回,所以当出现异常时我们需要对异常信息进行包装,抛一 个友好的信息给前端。

Hystrix 降级的使用比较简单

代码示例

/**
     * Command属性
     * execution.isolation.strategy  执行的隔离策略
     * THREAD 线程池隔离策略  独立线程接收请求
     * SEMAPHORE 信号量隔离策略 在调用线程上执行
     * <p>
     * execution.isolation.thread.timeoutInMilliseconds  设置HystrixCommand执行的超时时间,单位毫秒
     * execution.timeout.enabled  是否启动超时时间,true,false
     * execution.isolation.semaphore.maxConcurrentRequests  隔离策略为信号量的时候,该属性来配置信号量的大小,最大并发达到信号量时,后续请求被拒绝
     * <p>
     * circuitBreaker.enabled   是否开启断路器功能
     * circuitBreaker.requestVolumeThreshold  该属性设置在滚动时间窗口中,断路器的最小请求数。默认20,如果在窗口时间内请求次数19,即使19个全部失败,断路器也不会打开
     * circuitBreaker.sleepWindowInMilliseconds    改属性用来设置当断路器打开之后的休眠时间,休眠时间结束后断路器为半开状态,断路器能接受请求,如果请求失败又重新回到打开状态,如果请求成功又回到关闭状态
     * circuitBreaker.errorThresholdPercentage  该属性设置断路器打开的错误百分比。在滚动时间内,在请求数量超过circuitBreaker.requestVolumeThreshold,如果错误请求数的百分比超过这个比例,断路器就为打开状态
     * circuitBreaker.forceOpen   true表示强制打开断路器,拒绝所有请求
     * circuitBreaker.forceClosed  true表示强制进入关闭状态,接收所有请求
     * <p>
     * metrics.rollingStats.timeInMilliseconds   设置滚动时间窗的长度,单位毫秒。这个时间窗口就是断路器收集信息的持续时间。断路器在收集指标信息的时会根据这个时间窗口把这个窗口拆分成多个桶,每个桶代表一段时间的指标,默认10000
     * metrics.rollingStats.numBuckets   滚动时间窗统计指标信息划分的桶的数量,但是滚动时间必须能够整除这个桶的个数,要不然抛异常
     * <p>
     * requestCache.enabled   是否开启请求缓存,默认为true
     * requestLog.enabled 是否打印日志到HystrixRequestLog中,默认true
     *
     * @HystrixCollapser 请求合并
     * maxRequestsInBatch  设置一次请求合并批处理中允许的最大请求数
     * timerDelayInMilliseconds  设置批处理过程中每个命令延迟时间
     * requestCache.enabled   批处理过程中是否开启请求缓存,默认true
     * <p>
     * threadPoolProperties
     * threadPoolProperties 属性
     * coreSize   执行命令线程池的最大线程数,也就是命令执行的最大并发数,默认10
     */
    @HystrixCommand(fallbackMethod = "queryContentsFallback",
            commandKey = "queryContents",
            groupKey = "querygroup-one",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests",value = "100"),
                    @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"),
//                    @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000000000")
            },
            threadPoolKey = "queryContentshystrixJackpool", threadPoolProperties = {
//            @HystrixProperty(name = "coreSize", value = "100")
    })
           

指定降级方法

定义降级方法,降级方法的返回值和业务方法的方法值要一样

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

Hystrix 数据监控

Hystrix 进行服务熔断时会对调用结果进行统计,比如超时数、bad 请求数、降 级数、异常数等等都会有统计,那么统计的数据就需要有一个界面来展示, hystrix-dashboard 就是这么一个展示 hystrix 统计结果的服务。

Dashboard 工程搭建

pom.xml

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

启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
/*
* 监控界面:http://localhost:9990/hystrix
* 需要监控的端点(使用了hystrix组件的端点):http://localhost:8083/actuator/hystrix.stream
 *
* */
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashboardApplication.class,args);
//        new SpringApplicationBuilder(HystrixDashboardApplication.class).web(true).run(args);
    }
}
           

Dashboadr 界面

http://localhost:9990/hystrix

然后在界面中输入需要监控的端点 url:

http://localhost:8083/actuator/hystrix.stream

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断
架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

Hystrix熔断

熔断就像家里的保险丝一样,家里的保险丝一旦断了,家里就没点了,家里用电器功率高了就会导致保险丝端掉。在我们springcloud领域也可以这样理解,如果并发高了就可能触发hystrix的熔断。

熔断发生的三个必要条件:

  • 1、有一个统计的时间周期,滚动窗口

    相应的配置属性

    metrics.rollingStats.timeInMilliseconds

    默认10000毫秒

  • 2、请求次数必须达到一定数量

    相应的配置属性

    circuitBreaker.requestVolumeThreshold

    默认20次

  • 3、失败率达到默认失败率

    相应的配置属性

    circuitBreaker.errorThresholdPercentage

    默认50%

上述3个条件缺一不可,必须全部满足才能开启hystrix的熔断功能。

当我们的对一个线程池大小是100的方法压测时看看hystrix的熔断效果:

Jmeter压测:

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

Hystrix dashboard界面

架构师--SpringCloud学习笔记:三、springcloud熔断降级组件hystrix详解服务雪崩服务隔离Hystrix 服务隔离策略Hystrix 服务降级Hystrix 数据监控Hystrix熔断

可以看到失败率超过50%时,circuit的状态是open的。

熔断器的三个状态:

  • 1、关闭状态

    关闭状态时用户请求是可以到达服务提供方的

  • 2、开启状态

    开启状态时用户请求是不能到达服务提供方的,直接会走降级方法

  • 3、半开状态

    当hystrix熔断器开启时,过一段时间后,熔断器就会由开启状态变成半开状态。

    半开状态的熔断器是可以接受用户请求并把请求传递给服务提供方的,这时候如果远程调用返回成功,那么熔断器就会有半开状态变成关闭状态,反之,如果调用失败,熔断器就会有半开状态变成开启状态。

Hystrix功能建议在并发比较高的方法上使用,并不是所有方法都得使用的。

练习项目代码:https://share.weiyun.com/5bigglx

继续阅读