服务熔断Hystrix和Sentinel的使用方式

Hystrix组件

1、服务器容错核心知识

1.1、雪崩效应

​ 在微服务架构中,一个请求需要调用多个服务是非常常见的。如客户端访问A服务,而A服务需要调用B 服务,B服务需要调用C服务,由于网络原因或者自身的原因,如果B服务或者C服务不能及时响应,A服 务每处于阻塞状态,直到B服务C服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕, 导致服务簿痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难 性的严重后果,这就是服务故障的"雪崩"效应。

1.2、服务隔离

​ 将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其他模块,不影响整体的系统服务。

1.3、熔断降级

​ 熔断这一概念来源于电子工程中的熔断器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。熔断降级

所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的

1.4、服务限流

​ 限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量以到达保护系统的目的。一般来说系统的吞吐量是可以被测算的,为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。比如:推迟解决,拒绝解决,或者部分拒绝等等。

2、Hystrix

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

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

3、Rest实现服务熔断

3.1 基本配置

3.1.1、引入hystrix依赖

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

3.1.2、在启动类中激活hystrix

//激活Hystrix
@EnableCircuitBreaker
@SpringBootApplication
public class ConsumerFeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerFeignApplication.class,args);
    }
}

3.1.2、配置熔断出发的降级逻辑

/**
 * 降级方法
 *  和需要受到保护的方法的参数及返回值类型一致
 */
public User userFallBack(Long id){
    return new User();
}

3.1.4、在需要受到保护的接口上使用@HystrixCommand配置

/**
 * 使用注解配置熔断保护
 *  fallbackMethod:配置熔断之后的降级方法
 */
@HystrixCommand(fallbackMethod = "userFallBack")
@GetMapping("/getUserBalanceById/{id}")
public User getUserBalanceById(@PathVariable Long id){
    //根据服务注册名称获取服务实例列表
    String url = "http://user-service/user/getUserById/"+id;
    return restTemplate.getForObject(url,User.class);
}

超时设置

Hystrix默认超时时长为1s,超过1s后会自动触发熔断降级方法。可以修改配置参数:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000 #默认的连接超时时间是1s

3.2 RestTemplate统一的降级配置

3.2.1 配置统一降级方法

/**
 * 指定统一的降级方法
 *  没有参数
 */
public User defaultFallBack(){
    return new User();
}

3.2.2 配置统一降级方法

@RestController
@RequestMapping("/consumer")
/**
 * @DefaultProperties:指定此接口中公共的熔断设置
 *      如果在@DefaultProperties指定了公共的降级方法
 *      在@HystrixCommand中可以不用单独指定
 */
@DefaultProperties(defaultFallback = "defaultFallBack")
public class ConsumerController {...}

4、Feign实现服务熔断

引入依赖(feign中已经集成了Hystrix)

在feign中配置了开启Hystrix

feign:
  #配置日志级别
  client:
    config:
      USER-SERVICE:
        loggerLevel: FULL
  #开启对hystrix的支持
  hystrix:
    enabled: true

自定义一个接口的实现类,这个实现类就是熔断出发的降级逻辑

@Component
public class UserFeignClientCallBack implements UserFeignClient{
    /**
     * 熔断降级的方法
     */
    public User getUserById(Long id) {
        return new User();
    }
}

修改FeignClient接口,添加降级方法的支持

/**
 * 声明需要调用的微服务名称
 * @FeignClient
 *      *name:服务提供者的名称
 *      *fallback:配置熔断降级的方法配置类
 */
@FeignClient(name = "USER-SERVICE",fallback = UserFeignClientCallBack.class)
public interface UserFeignClient {

    @RequestMapping(value = "/user/getUserById/{id}",method = RequestMethod.GET)
    User getUserById(@PathVariable("id") Long id);

}

5、Hystrix设置监控信息

基本监控

引入坐标

<!--引入Hystrix的监控信息-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.3.RELEASE</version>
</dependency>

在启动类上配置

//开启Feign注解
@EnableFeignClients
//激活Hystrix
@EnableCircuitBreaker
@SpringBootApplication
public class ConsumerFeignApplication {...}

暴露所有actuator监控的断点

management:
  endpoints:
    web:
      exposure:
        include: '*'

在页面上访问http://ip:port/actuator/hystrix.stream

web监控页面

引入坐标

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

激活hystrix的web监控平台

//开启Feign注解
@EnableFeignClients
//激活Hystrix
@EnableCircuitBreaker
//激活hystrix的web监控平台
@EnableHystrixDashboard
@SpringBootApplication
public class ConsumerFeignApplication {...}

打开监控页面

​ http://ip:port/hystrix

​ 输入上一步的stream路径

Turbine 熔断器聚合统一监控

新建项目引入坐标

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
    <version>2.2.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>

添加配置项

server:
  port: 8031
spring:
  application:
    name: hystrix-trubine
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9001/eureka/
  instance:
    prefer-ip-address: true
turbine:
  # 要监控的微服务列表,多个用','隔开
  app-config: consumer-service
  cluster-name-expression: "'default'"

配置启动项

//激活turbine配置
@EnableTurbine
@EnableHystrixDashboard
@SpringBootApplication
public class TurbineApplication {
    public static void main(String[] args) {
        SpringApplication.run(TurbineApplication.class,args);
    }
}

在监控页面输入turbine监控流查看聚合监控

hystrix可以对请求失败的请求,以及被拒绝或者超时的请求进行统一的降级处理。

6、断路器

断路器状态

Closed(关闭),Open(开启),Half Open(半开)

​ Closed(关闭)

所有的请求都可以正常访问

可配置请求次数大于20次,且存在50%的失败概率

​ Open(开启)

所有请求会进入到降级方法中

​ Half Open(半开)

维持Open状态一段时间(默认5s),然后进入到半开状态(尝试释放一个请求到远程微服务发起调用)

如果释放的请求可以正常访问,就会关闭断路器

如果释放的请求不能正常访问,继 续保持开启状态5s

断路器的隔离策略

微服务使用Hystrix熔断器实现了服务的自动降级,让微服务具备自我保护的能力,提升了系统的稳定性,比较好的解决雪崩效应。其使用方式目前支持两种策略:

  • 线程池隔离策略:使用一个线程池来存储当前的请求,线程池对请求做处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据缓存到线程池队列里慢慢处理)
  • 信号量隔离策略:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃该类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流浪洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)

线程池和信号量两种策略功能支持对比:

断路器的隔离策略

配置策略:

  • hystrix.command.default.execution.isolation.strategy: #配置隔离策略
    • ExecutionIsolationStrategy.SEMAPHORE #信号量隔离
    • ExecutionIsolationStrategy.THREAD #线程池隔离
  • hystrix.command.default.execution.isolation.maxConcurrentRequests:最大信号量上限

hystrix执行过程

hystrix执行过程

Sentinel组件

1、概述

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。

sentinel具有以下特征

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

名词解释

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

使用sentinel进行熔断保护,主要分为几个步骤:

1. 定义资源
2. 定义规则
3. 检验规则是否生效

资源

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

规则

围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整

sentinel主要特性

主要特性

功能对比

SentinelHystrixresilience4j
隔离策略信号量隔离(并发线程数限流)线程池隔离/信号量隔离信号量隔离
熔断降级策略基于响应时间、异常比率、异常数基于异常比率基于异常比率、响应时间
实时统计实现滑动窗口(LeapArray)滑动窗口(基于 RxJava)Ring Bit Buffer
动态规则配置支持多种数据源支持多种数据源有限支持
扩展性多个扩展点插件的形式接口的形式
基于注解的支持支持支持支持
限流基于 QPS,支持基于调用关系的限流有限的支持Rate Limiter
流量整形支持预热模式、匀速器模式、预热排队模式不支持简单的 Rate Limiter 模式
系统自适应保护支持不支持不支持
控制台提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等简单的监控查看不提供控制台,可对接其它监控系统

hystrix迁移方案

Hystrix 功能迁移方案
线程池隔离/信号量隔离Sentinel 不支持线程池隔离;信号量隔离对应 Sentinel 中的线程数限流,详见此处
熔断器Sentinel 支持按平均响应时间、异常比率、异常数来进行熔断降级。从 Hystrix 的异常比率熔断迁移的步骤详见此处
Command 创建直接使用 Sentinel SphU API 定义资源即可,资源定义与规则配置分离,详见此处
规则配置在 Sentinel 中可通过 API 硬编码配置规则,也支持多种动态规则源
注解支持Sentinel 也提供注解支持,可以很方便地迁移,详见此处
开源框架支持Sentinel 提供 Servlet、Dubbo、Spring Cloud、gRPC 的适配模块,开箱即用;若之前使用 Spring Cloud Netflix,可迁移至 Spring Cloud Alibaba

2、sentinel管理控制台

2.1 概述:

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。另外,鉴权在生产环境中也必不可少。

Sentinel 控制台包含如下功能:

2.2 启动控制台

2.2.1 获取sentinel控制台

可以从 release 页面 下载最新版本的控制台 jar 包。

您也可以从最新版本的源码自行构建 Sentinel 控制台:

  • 下载 控制台 工程
  • 使用以下命令将代码打包成一个 fat jar: mvn clean package
2.2.2 启动

注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。

使用命令启动控制台:

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080

从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel。可以参考 鉴权模块文档 配置用户名和密码。

2.2.3 客户端接入控制台

控制台启动后,客户端需要按照以下步骤接入到控制台。

2.3.1 引入jar包

客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。您可以通过 pom.xml 引入 JAR 包:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>x.y.z</version>
</dependency>
2.3.2 配置启动参数

启动时加入 JVM 参数 -Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口。若启动多个应用,则需要通过 -Dcsp.sentinel.api.port=xxxx 指定客户端监控 API 的端口(默认是 8719)。

从 1.6.3 版本开始,控制台支持网关流控规则管理。您需要在接入端添加 -Dcsp.sentinel.app.type=1 启动参数以将您的服务标记为 API Gateway,在接入控制台时您的服务会自动注册为网关类型,然后您即可在控制台配置网关规则和 API 分组。

除了修改 JVM 参数,也可以通过配置文件取得同样的效果。更详细的信息可以参考 启动配置项

2.3.3 触发客户端初始化

确保客户端有访问量,Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。

注意:您还需要根据您的应用类型和接入方式引入对应的 适配依赖,否则即使有访问量也不能被 Sentinel 统计。

3、使用sentinel组件

3.1、管理控制台

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

启动成功 localhost:8080/

访问的用户名/密码:sentinel/sentinel

3.2、将所有的服务交给控制台管理

客户端接入Sentinel管理控制台

  1. 在客户端(需要管理微服务上)引入坐标

    父项目引入坐标:

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.2.0.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    

    子项目引入坐标:

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        <version>2.2.0.RELEASE</version>
    </dependency>
    
  2. 在客户端配置启动参数

    sentinel:
      transport:
        dashboard: localhost:8080 #sentinel 控制中心ip:port
    

    sentinel默认为懒加载,启动以后需要访问资源路径才能在管理控制台查看到监控信息。

3.3 通用资源保护

	/**
     * blockHandler:声明熔断时的限流方法(在抛出BlockException异常是触发,限流方法的参数需要添加BlockException)
     * fallback:抛出异常时的降级方法
     * value:自定义资源名称(默认为当前全类名.方法名)
     */
    @SentinelResource(value = "getUserBalanceById",fallback = "userFallBack",blockHandler = "userBlockHandler")
    @GetMapping("/getUserBalanceById/{id}")
    public User getUserBalanceById(@PathVariable Long id) throws MyException {
        if(id!=26){
            throw new MyException("error");
        }
        String url = "http://localhost:8001/user/getUserById/"+id;
        //根据服务注册名称获取服务实例列表
        url = "http://user-service/user/getUserById/"+id;
        return restTemplate.getForObject(url,User.class);
    }

    /**
     * 定义降级逻辑
     * sentinel和hystrix不同
     *   可以指定熔断执行的降级方法
     *   可以指定抛出异常执行的降级方法
     */
    public User userBlockHandler(Long id, BlockException e){
        User user = new User();
        user.setName("断了");
        user.setId(id);
        return user;
    }

    public User userFallBack(Long id){
        User user = new User();
        user.setName("异常");
        user.setId(id);
        return user;
    }

3.4 RestTemplate的资源保护

启动类配置@SentinelRestTemplate

	/**
     * sentinel支持对RestTemplate的服务调用使用sentinel方法.
     * 在构造RestTemplate对象的时候,只需要加载@SentinelRestTemplate即可
     *
     *  @SentinelRestTemplate
     *      blockHandler    :限流方法
     *      blockHandlerClass:限流配置类
     *      fallback        :降级方法
     *      fallbackClass   :降级配置类
     *
     *  资源名:
     *      httpmethod:schema://host:port/path 协议://主机:端口/路径
     *      httpmethod:schema://host:port 协议://主机:端口
     */
    //使用@LoadBalanced注解实现负载均衡
    @Bean
    @LoadBalanced
    @SentinelRestTemplate(fallbackClass = ExceptionUtils.class,fallback = "handlerFallback",
            blockHandlerClass = ExceptionUtils.class,blockHandler = "handlerBlock")
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

编辑通用降级逻辑


public class ExceptionUtils {
    /**
     * 静态方法
     * 返回值:SentinelClientHttpResponse
     * 参数:HttpRequest,byte[],ClientHttpRequestExecution,BlockException
     */
    //异常降级业务逻辑
    public static SentinelClientHttpResponse handlerFallback(HttpRequest request, byte[] body,
                                                             ClientHttpRequestExecution execution,
                                                             BlockException exception) {
        System.out.println("fallback" + exception.getClass().getCanonicalName());
        User user = new User();
        user.setName("异常熔断降级");
        return new SentinelClientHttpResponse(JSON.toJSONString(user));
    }

    //限流熔断业务逻辑
    public static SentinelClientHttpResponse handlerBlock(HttpRequest request, byte[] body,
                                                          ClientHttpRequestExecution execution,
                                                          BlockException exception) {
        System.out.println("block" + exception.getClass().getCanonicalName());
        User user = new User();
        user.setName("限流熔断降级");
        return new SentinelClientHttpResponse(JSON.toJSONString(user));
    }
}

3.5 Feign实现熔断

Sentinel适配了Feign组件。如果想使用,除了引入sentinel-starter的依赖外还需要2个步骤:

  • 配置文件打开sentinel对feign的支持:feign.sentinel.enabled=true
  • 加入openfeign starter依赖是sentinel starter中的自动化配置类生效
  1. 引入依赖

    <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
                <version>2.2.2.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
                <version>2.2.1.RELEASE</version>
            </dependency>
    
  2. 开启sentinel支持

    在工程的application.yml中添加sentinel对feign的支持

    feign:
      sentinel:
        enabled: true
    
  3. 配置FeignClient(与使用Hystrix类似)

    声明fallback对应的处理类

    /**
     * 声明需要调用的微服务名称
     * name:服务提供者的名称
     */
    @FeignClient(name = "USER-SERVICE",fallback = UserFeignClientCallBack.class)
    public interface UserFeignClient {
        //配置需要调用的微服务接口
        @RequestMapping(value = "/user/getUserById/{id}", method = RequestMethod.GET)
        User getUserById(@PathVariable("id") Long id);
    
    }
    
  4. 配置熔断降级方法

    @Component
    public class UserFeignClientCallBack implements UserFeignClient{
        /**
         * 熔断降级的方法
         */
        public User getUserById(Long id) {
            User user = new User();
            user.setName("降级");
            return user;
        }
    }
    

4、sentinel加载本地设置

一条限流规则以下几个因素组成:

resource:资源名,即限流规则的作用对象

count:限流阈值

grade:限流阈值类型(QPS或并发线程数)

limitApp:流控针对的调用来源,若为default则不区分调用来源

strategy:调用关系限流策略

controlBehavior:流量控制效果(直接拒绝、WarmUp、匀速排队)

Java代码 RuleConstant

配置文件添加如下配置

#通过文件读取限流规则

spring:
  cloud:
	sentinel:
      transport:
        dashboard: localhost:8080
      datasource:
        ds1:
          file:
            file: classpath:flowrule.json
            data-type: json
            rule-type: flow

flowjson内容:

[
  {
    "resource": "getUserBalanceById",
    "controlBehavior": 0,
    "count":1,
    "grade":1,
    "limitApp": "default",
    "strategy": 0
  }
]
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页