Sentinel: 分布式系统的流量防卫兵


官方文档

1 Sentinel简介

官方文档

1.1官方介绍

Sentinel 是什么?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

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

1.2 总结

Sentinel 是分布式系统的防御系统。以流量为切入点,通过动态设置的流量控制、服务熔断等手段达到保护系统的目的,通过服务降级增强服务被拒用户的体验。

2 服务降级

服务降级是一种增强用户体验的方式。当用户的请求由于各种原因被拒后,系统返回一个事先设定好的、用户可以接受的,但又令用户并不满意的结果。这种请求处理方式称为服 务降级。
案例完整源码

2.1 降级实现方式分类

对于 Sentinel,服务降级的实现方式根据消费者类型的不同,其支持两种方式:

  • Sentinel 式降级:通过 Sentinel 自身的 API 实现的降级方式,适用于任意消费者类型。而根据降级方法应用范围、定义位置及可维护性的不同,又可分为两种:
    方法级降级:降级方法与原方法定义在同一个类中,其仅是本类中的原方法可以使用。
    类级降级:降级方法定义在专门的一个类中,其是一个可以被共享的降级类。该类中的所有方法均为降级方法,所以便于维护与管理。
  • Feign 式降级:通过 OpenFeign 的 API 实现的降级方式,仅适用于 Feign 客户端的消费者类型。其只有类级降级方式。

2.2 Sentinel 式方法级降级

(1)添加依赖

在原有的feign-nacos项目中添加依赖

  <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        <version>2.2.1.RELEASE</version>
      </dependency>

(2) 修改处理器类

    /**
     * 定义了降级
     */
    @SentinelResource(fallback = "getHandleFallback")
    @GetMapping("/get/{id}")
    public DepartVO getHandle(@PathVariable("id") int id) {
        return departService.getDepartById(id);
    }

    public DepartVO getHandleFallback(int id, Throwable e) {
        DepartVO departVO = new DepartVO();
        departVO.setId(id);
        departVO.setName("degrade-method-" + id + "-" + e.getMessage());
        return departVO;
    }

(3) 测试

  1. 只启动消费者,访问接口发现走了降级方法。

在这里插入图片描述

  1. 启动消费者和生产者无异常,正常访问接口
  2. 在消费者端模拟异常并启动,访问接口发现走了降级方法。
    在这里插入图片描述
    思考了一下,这里是为了模拟降级服务而简单的处理。实际中应该会具体实现降级业务,针对异常做些处理。

2.3 Sentinel 式类级降级

(1) 定义降级类

public class DepartServiceFallback {

    public static boolean saveFallback(DepartVO depart, Throwable e) {
        System.out.println("getHandle()执行异常 " + depart.toString());
        return false;
    }

    public static List<DepartVO> listFallback() {
        System.out.println("listHandle()执行异常 ");
        DepartVO departVO = new DepartVO();
        List<DepartVO> arrayList = new ArrayList<>();
        departVO.setId(1);
        departVO.setName("no any depart");
        arrayList.add(departVO);
        return arrayList;
    }

}

(2) 修改 DepartController 处理器

    /**
     *@SentinelResource注解中指定降级方法和降级方法对应的类
     */
    @SentinelResource(fallback = "saveFallback", fallbackClass = DepartServiceFallback.class)
    @PostMapping("/save")
    public boolean saveHandle(@RequestBody DepartVO depart) {
        return departService.saveDepart(depart);
    }
    
    @SentinelResource(fallback = "listFallback", fallbackClass = DepartServiceFallback.class)
    @GetMapping("/list")
    public List<DepartVO> listHandle() {
        return departService.listAllDeparts();
    }

(3)测试

只启动消费者
在这里插入图片描述

2.4 Feign 式类级降级

(1)添加依赖

消费者端项目中添加依赖

  <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        <version>2.2.1.RELEASE</version>
      </dependency>

(2) 修改配置文件

feign:        
  sentinel: # 开启sentinel对feign的支持
    enabled: true

(3) 定义降级类

在feign对外接口中添加DepartServiceFallback降级类
降级类实现feign接口,在方法中根据实际业务完成降级业务
在这里插入图片描述

// 降级类:实现了Feign接口
@Component
//@RequestMapping("/fallback/provider/depart")  // 其开头必须是/fallback
public class DepartServiceFallback implements DepartService {
    @Override
    public boolean saveDepart(DepartVO depart) {
        System.out.println("执行saveDepart()的服务降级处理方法");
        return false;
    }

    @Override
    public boolean removeDepartById(int id) {
        System.out.println("执行removeDepartById()的服务降级处理方法");
        return false;
    }

    @Override
    public boolean modifyDepart(DepartVO depart) {
        System.out.println("执行modifyDepart()的服务降级处理方法");
        return false;
    }

    @Override
    public DepartVO getDepartById(int id) {
        System.out.println("执行getDepartById()的服务降级处理方法");
        DepartVO depart = new DepartVO();
        depart.setId(id);
        depart.setName("degrade-feign");
        return depart;
    }

    @Override
    public List<DepartVO> listAllDeparts() {
        System.out.println("执行listAllDeparts()的服务降级处理方法");
        return null;
    }
}

(4)修改feign接口

//在注解中指定降级类
@FeignClient( value="feign-nacos-provider-modules", path = "/provider/depart",
fallback = DepartServiceFallback.class)
public interface DepartService {
    @PostMapping("/save")
    boolean saveDepart(@RequestBody DepartVO depart);

    @DeleteMapping("/del/{id}")
    boolean removeDepartById(@PathVariable("id") int id);

    @PutMapping("/update")
    boolean modifyDepart(@RequestBody DepartVO depart);

    @GetMapping("/get/{id}")
    DepartVO getDepartById(@PathVariable("id") int id);

    @GetMapping("/list")
    List<DepartVO> listAllDeparts();
}

(5)测试

只启动消费者,模拟生产者异常。访问删除接口。结果发现执行了降级方法
在这里插入图片描述

3 Sentinel Dashboard

Sentinel 控制台(官方链接)

3.1 简介

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。

Sentinel 控制台包含如下功能:

  • 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
  • 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
  • 规则管理和推送:统一管理推送规则。
  • 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。

注意:Sentinel 控制台目前仅支持单机部署。Sentinel 控制台项目提供 Sentinel 功能全集示例,不作为开箱即用的生产环境控制台,不提供安全可靠保障。若希望在生产环境使用请根据文档自行进行定制和改造。

3.2 下载

直接从官方下载打包好的 Sentinel Dashboard 启动运行

在这里插入图片描述
组件版本关系
Sentinel Dashboard 版本需要和Spring Cloud Alibaba Version对应,项目中Spring Cloud Alibaba Version为2.2.1.RELEASE,我们选用1.7.1以上版本。1.8版本和1.7版本界面变化有些大,选用新一点版本使用1.8.0下载
在这里插入图片描述
在这里插入图片描述

3.3 启动

启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本
在这里插入图片描述

java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888 
-Dproject.name=sentinel-dashboard 
-Dsentinel.dashboard.auth.username=sentinel 
-Dsentinel.dashboard.auth.password=sentinel -jar sentinel-dashboard-1.8.0.jar

在这里插入图片描述

3.4 访问

http://localhost:8888/#/login
在这里插入图片描述

在这里插入图片描述

4 服务熔断

项目案例源码

4.1熔断概念

服务雪崩和熔断介绍

(1) 服务雪崩
如果说服务流控是为了在高并发场景下不至于将系统压垮,那么服务熔断则是为了在外部环境不通畅场景下,不至于将系统拖垮,也就是为了防止服务雪崩的发生。
在这里插入图片描述

在复杂的系统中,经常会出现 A 依赖于 B,B 依赖于 C,C 依赖于 D,……这种依赖将会产生很长的调用链路,这种复杂的调用链路称为 1->N 的扇出。
如果在 A 的调用链路上某一个或几个被调用的子服务不可用或延迟较高,则会导致调用A 服务的请求被堵住(等待超时)。堵住的 A 请求会消耗占用系统的线程、IO 等资源,当对A 服务的请求越来越多,占用的计算机资源越来越多的时候,会导致系统瓶颈出现,造成其他的请求同样不可用,最终导致业务系统崩溃,这种现象称为雪崩效应

(2) 服务熔断
Hystrix官网
为了防止服务雪崩的发生,在发现了对某些资源请求的响应缓慢或调用异常较多时,直接将对这些资源的请求掐断一段时间。而在这段时间内的请求将不再等待超时,而是直接返回事先设定好的降级结果。这些请求将不占用系统资源,从而避免了服务雪崩的发生。这就是服务熔断。

4.2 动态设置

对于服务熔断规则,可以通过 Sentinel Dashboard 进行动态设置。

4.2.1 修改处理器类

在消费者类处理器上配置降级名称,后续降级名称需要在sentinel dashboard中使用。这样客户端上配置的降级规则才能够知道给谁使用。

    /**
     * 定义了降级
     */
    @SentinelResource(value = "slowRequstDegradeRule",fallback = "getHandleFallback")
    @GetMapping("/get/{id}")
    public DepartVO getHandle(@PathVariable("id") int id) {
        return departService.getDepartById(id);
    }

在这里插入图片描述

4.2.2 修改配置文件

spring:
  application:
    name: feign-nacos-consumer  # 微服务名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848   # nacos discovery地址
    sentinel:
      transport:
        dashboard: localhost:8888  # Sentinel客户端地址
        port: 8197 # 服务和客户端通信端口,在客户端上配置会生效到服务上需要发送请求
      eager: true # 开启配置后立即生效

在这里插入图片描述

4.2.3 在sentinel 客户端设置降级规则

先启动消费者服务,在进入sentinel控制台。
在这里插入图片描述

4.2.4 修改提供者工程

设置睡眠时间,模拟接口请求慢。设置完成启动提供者

    @GetMapping("/get/{id}")
    public DepartVO getHandle(@PathVariable("id") int id) throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(500);
        DepartVO departVO = new DepartVO();
        departVO.setId(1);
        departVO.setName("liming");
        return departVO;
    }

在这里插入图片描述

4.2.5 测试

  1. 单次访问,可以发现能够正常取值。

http://localhost:8080/consumer/depart/get/1
在这里插入图片描述

  1. 在浏览器中快速按F5不断刷新接口,连续刷新8次
    注意 我们使用的sentinel版本是1.7.1的,这个版本不支持修改比例阈值(默认为1),sentinel 客户端是1.8.0界面上虽然有比例阈值修改,但是不生效的。
    在这里插入图片描述

3.紧接着再次刷新接口

还是返回的降级结果。设置了熔断时长为20s,在这20秒访问会直接走降级逻辑。

4.3 熔断策略

(1)响应时间 RT

在这里插入图片描述

慢调用比。该策略需要设置用于界定慢调用的响应时间阈值 RT(Response Time),
当请求的响应时间大于该值时,将该请求统计为慢调用。若要发生熔断,
在 1 秒内收到的请求数 量不能小于“最小请求数”,且慢调用占比不能低于“比例阈值”。
当触发熔断,则会在“熔断时长”内不再对请求进行处理,即熔断期间再来的请求,
将直接进行降级响应。

(2)异常比

在这里插入图片描述

异常比。该策略需要设置异常请求在统计时间窗口内所有请求中的占比,异常比率的阈 
值范围是 [0.0, 1.0],代表 0% - 100%。当异常请求比例大于该值时则会触发熔断。
默认情况下,统计时间窗口大小为 1 秒,期间接收到的请求至少 5 个。
发生熔断后,熔断时长为指定的时长。熔断期间再来的请求,将直接地降级响应。

(3)异常数

在这里插入图片描述

异常数。该策略需要设置在统计时间窗口内所接收到的异常请求的数量。
当异常请求数量大于该值时则会触发熔断。默认情况下,统计时间窗口大小为 1 分钟,
注意,是 1 分钟。发生熔断后,熔断时长为指定的时长。熔断期间再来的请求,
将直接地降级响应。

4.4 代码设置

通过 Dashboard 平台进行熔断规则设置,粒度有些粗,有些属性只能通过代码来设置。而代码中的 API,在不同的 Sentinel 版本中,是有所不同的。
熔断规则直接定义在代码中,当应用启动时完成熔断规则的创建与初始化。这个熔断规则在 Dashboard 中也是可以查看到并且进行编辑的,编辑后以动态编辑的规则为准。

添加降级规则配置类

@Configuration
public class hystrixRuleConfig {

    /**
     * 初始化生效的降级规则
     */
    @Bean
    public void initRule() {
        List<DegradeRule> rules = new ArrayList<>();
        rules.add(slowRequestDegradeRule());
        rules.add(errorRatioDegradeRule());
        rules.add(errorCountDegradeRule());
        DegradeRuleManager.loadRules(rules);
    }

    /**
     * 慢调用
     */
    @Bean
    public DegradeRule slowRequestDegradeRule() {
        //定义降级规则
        DegradeRule degradeRule = new DegradeRule();
        //指定降级规则名称
        degradeRule.setResource("slowRequestDegradeRule");
        //指定熔断策略为Rt(response time)
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        //指定熔断阈值为200ms(请求响应时长大于200ms,统计为慢调用)
        degradeRule.setCount(200);
        //指定熔断时长60s
        degradeRule.setTimeWindow(60);
        //指定在1秒的统计时间窗内至少要5个请求
        degradeRule.setMinRequestAmount(5);
        //指定若要启动熔断,则在1秒内至少要3次慢请求
        degradeRule.setRtSlowRequestAmount(3);
        return degradeRule;
    }

    /**
     * 异常比
     */
    @Bean
    public DegradeRule errorRatioDegradeRule() {
        DegradeRule degradeRule = new DegradeRule();
        //指定降级规则名称
        degradeRule.setResource("errorRatioDegradeRule");
        //指定熔断策略为异常比
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
        //指定熔断阈值为50%
        degradeRule.setCount(0.5);
        //指定熔断时长60s
        degradeRule.setTimeWindow(60);
        //指定在1秒的统计时间窗内至少要5个请求
        degradeRule.setMinRequestAmount(5);
        return degradeRule;
    }

    /**
     * 异常数
     */
    @Bean
    public DegradeRule errorCountDegradeRule() {
        DegradeRule degradeRule = new DegradeRule();
        degradeRule.setResource("errorCountDegradeRule");
        //指定熔断策略为异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        //指定熔断阈值为3
        degradeRule.setCount(3);
        //指定熔断时长60s
        degradeRule.setTimeWindow(60);
        //指定在1秒的统计时间窗内至少要5个请求
        degradeRule.setMinRequestAmount(5);
        return degradeRule;
    }
}


使用降级

启动消费者服务后我们观察一下控制台,发现三个降级规则都已成功注册。
无测试异常在这里插入图片描述
连续发送三次请求
在这里插入图片描述

5 服务流控

项目案例源码

5.1 流控概念

流控,即流量控制,也称为限流。Sentinel 实现流控的原理是监控应用流量的 QPS 或并 发线程数等指标,当达到指定的阈值时对再来的请求进行进行控制,以避免被瞬时的流量高 峰冲垮,从而保障应用的高可用性。

5.2 动态设置

流控规则直接通过 Sentinel Dashboard 定义,该规则可以随时修改而不需要重启应用该 规则的应用程序。所以这种流控是一种动态流控。

(1) 修改配置文件

在这里插入图片描述

server:
  port: 8080
spring:
  application:
    name: feign-nacos-consumer  # 微服务名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848   # nacos discovery地址
    sentinel:
      transport:
        dashboard: localhost:8888  # Sentinel客户端地址
        port: 8197 # 服务和客户端通信端口,在客户端上配置会生效到服务上需要发送请求
      eager: true # 开启配置后立即生效

(2)修改处理器 1-指定流控规则

在这里插入图片描述

 /**
     * 定义了降级,和限流
     */
    @SentinelResource(value = "qpsFlowRule",
            blockHandler = "getBlockHandler",
            fallback = "getHandleFallback")
    @GetMapping("/get/{id}")
    public DepartVO getHandle(@PathVariable("id") int id) {
        return departService.getDepartById(id);
    }

    public DepartVO getBlockHandler(int id, BlockException e) {
        DepartVO departVO = new DepartVO();
        departVO.setId(id);
        departVO.setName("flow-control" + id + "-" + e.getMessage());
        return departVO;
    }

    public DepartVO getHandleFallback(int id, Throwable e) {
        DepartVO departVO = new DepartVO();
        departVO.setId(id);
        departVO.setName("degrade-method-" + id + "-" + e.getMessage());
        return departVO;
    }

(3) dashboard 设置流控规则

在这里插入图片描述
每秒访问量超过一次时,就会立刻进入限流函数。

(4)测试

http://localhost:8080/consumer/depart/get/1
在这里插入图片描述

5.3 代码设置

(1)添加限流配置类

@Configuration
public class flowRuleConfig {

    @Bean
    public void initFlowRule(){
        List<FlowRule> flowRules=new ArrayList<>();
        flowRules.add(qpsFlowRule());
        FlowRuleManager.loadRules(flowRules);
    }

    @Bean
    public FlowRule qpsFlowRule(){
        FlowRule flowRule = new FlowRule();
        flowRule.setResource("qpsFlowRule");
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        flowRule.setCount(1);
        flowRule.setLimitApp("default");
        return flowRule;
    }
}

测试

项目重新启动,限流配置会注册到控制台在这里插入图片描述


版权声明:本文为weixin_43811057原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。