Sentinel

  • 官网
  • 轻量级的流量控制、熔断降级 Java 库
  • Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
  • Sentinel 分为两部分:核心库(Java 客户端)不依赖任何框架/库,能够运行在 Java8 以上运行时环境,同时对 Dubbo、SpringCloud 框架也有较好的支持;控制台(DashBoard)主要负责管理推送规则、监控、管理机器信息等

下载

  • 注意 docker 安装不行,一直空白界面,采用多种方式例如添加配置 client-ip 仍不行,错误一直超时。可能的原因是 sentinel和部署的微服务一定要在同一个内网中
  • docker 安装参考
  • 最后使用本地运行 sentinel 解决,下载地址 sentinel:1.8.6
  • 启动命令:java -jar sentinel-dashboard-1.8.6.jar --server.port=8081 alt

主要特性

alt


基本概念

alt


熔断框架比较

alt



服务限流

  • Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果
  • 流量控制有以下几个角度:
    1. 资源的调用关系,例如资源的调用链路,资源和资源之间的关系
    2. 运行指标,例如 QPS、线程池、系统负载等
    3. 控制的效果,例如直接限流、冷启动、排队等

流控规则

  • 资源名:唯一名称,默认请求路径
  • 针对来源:Sentinel 可以针对调用者进行限流,填写微服务名,默认 default(不区分来源)
  • 阈值类型/单机阈值
    1. QPS(每秒的请求数量):当调用该 api 的 QPS 达到阈值的时候,进行限流
    2. 线程数:当调用该 api 的线程数达到阈值的时候,进行限流

alt


流控模式

  • 直接:api 达到限流条件时,直接限流
  • 关联:当关联的资源达到阈值时,就限流自己;可以通过 JMeter(并发)、PostMan(串行) 测试
  • 链路:只记录指定链路上的流量,指定资源从入口资源进来的流量,如果达到阈值,就进行限流(api 级别的针对来源)

流控效果

  • 快速失败:直接失败,抛出异常

alt

  • 预热(Warm Up):根据 codeFactor(冷加载因子,默认3)的值,系统最开始的初始阈值为 阈值/codeFactor ,然后经过预热时长才慢慢达到设置的 QPS 阈值。应用于秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值

  • 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置 QPS,否则无效;对应的算法是漏桶算法;主要用于处理间隔性突发的流量,例如消息队列。在某一秒有大量请求到来,而接下来的几秒则处于空闲状态,希望系统能过在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求


限流提示

  • sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
  • 自定义提示:通过注解 @SentinelResource(value = "testHotKey", blockHandler = "dealHandler_testHotKey"),处理的是 sentinel 控制台配置的违规情况,有 blockHandler 方法兜底处理,不会管运行时异常;fallback 属性管理运行时异常


降级规则

  • RT(平均响应时间,秒级)
    1. 平均响应时间超出阈值 且 在 1s 内通过的请求 >= 5,两个条件同时满足后触发降级
    2. 当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断
    3. RT 最大为4900,仍需更大需要修改 -Dcsp.sentinel.statistic.max.rt=XXX 生效
  • 异常比(秒级):QPS(资源每秒请求量) >= 5 且 异常比例(每秒的)超过阈值时,触发降级;当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断;在时间窗口期结束后,关闭降级
  • 异常数(分钟级):异常数(每分钟)超过阈值时,触发降级;时间窗口期结束后,关闭降级


热点规则

  • 热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效
  • 例如:方法里面的第一个参数(指的是后台方法里的第一个参数而不是前端传入的第一个参数)只要 QPS 超过每秒1次,马上进行降级处理
/**
     * sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
     * 自定义限流异常,testHotKey为资源名;blockHandler为fallback方法
     *
     * @SentinelResource 处理的是 sentinel 控制台配置的违规情况,有 blockHandler 方法配置的兜底处理
     * 对于 RuntimeException 异常,例如 int age = 10 / 0,会走异常,@SentinelResource 注解不管
     * @param p1
     * @param p2
     * @return
     */
    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey", blockHandler = "dealHandler_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1, @RequestParam(value = "p2",required = false) String p2){
        return "------testHotKey";
    }

    public String dealHandler_testHotKey(String p1, String p2, BlockException exception) {
        return "-----dealHandler_testHotKey";
    }
  • 参数例外项:某些时候我们期望参数是某个特殊值的时候,它的限流值和平时不一样

alt



系统规则

  • 官网
  • 系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和 并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
  • 系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量,比如 web 服务或者 Dubbo 服务端接收的请求,都属于入口流量

支持模式

  • Load 自适应(仅对 linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR阶段)。系统容量由系统的 maxQPS * minRT 估算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏
  • 平均 RT:当单台机器上所有入口流量的平均 RT达到阈值即触发系统保护,单位是毫秒
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护


@SentinelResource 注解

  • blockHandler 管理配置违规情况
  • fallback 管理运行时异常,也就是业务代码异常
  • 同时配置同时出问题,blockHandler > fallback
/**
     * id = 4, 抛出运行时异常,会走 fallback 配置的方法,只负责业务异常
     * blockHandler 负责在 sentinel 里面配置的降级限流
     * 同时配置,blockHandler > fallback
     * @param id
     * @return
     */
    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback", blockHandler = "blockHandler", fallback = "blockFallBack")
    public CommonResult<Payment> fallback(@PathVariable Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);

        if (id == 4) {
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
        } else if (result.getData() == null) {
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }

    /**
     * 业务类异常
     * @param id
     * @param throwable
     * @return
     */
    public CommonResult blockFallBack(@PathVariable Long id, Throwable throwable) {
        return new CommonResult(4444, "运行时异常,fallback跳转,blockException: " + throwable.getMessage(), new Payment(id, "null"));
    }


    /**
     * sentinel控制台配置异常
     * @param id
     * @param blockException
     * @return
     */
    public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
        return new CommonResult<>(4445, "sentinel里面配置异常,blockHandler-sentinel限流, 无此流水: blockException  " + blockException.getMessage(), new Payment(id, "null"));
    }

按照资源名称限流

  • @SentinelResource(value = "byResource", blockHandler = "handleException"),其中 value 属性对应的就是资源名
  • 没有下划线 /

alt


按照 URL 地址限流

  • @GetMapping 对应URL,有下划线 /

alt


客户自定义限流处理逻辑

  • sentinel 控制台需要通过资源名配置,URL配置不起作用
  • @SentinelResource(value = "customerBlockHandler", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2");blockHandlerClass 对应的是类里面的具体方法 handleException2
/**
     * 自定义通用的限流处理逻辑,sentinel 控制台需要通过资源名配置,URL配置不起作用
     * blockHandlerClass = CustomerBlockHandler.class
     * blockHandler = handleException2
     * 上述配置:找CustomerBlockHandler类里的handleException2方法进行兜底处理
     */
    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2")
    public CommonResult customerBlockHandler() {
        return new CommonResult(200,"按客户自定义限流处理逻辑");
    }


/**
 * @author SHshuo
 * @data 2023/2/3--10:32
 * 自定义通用的限流处理逻辑
 */
public class CustomerBlockHandler {

    public static CommonResult handleException2(BlockException exception){
        return new CommonResult(2022,"自定义的限流处理信息......handleException2");
    }

    public static CommonResult handleException(BlockException exception){
        return new CommonResult(2022,"自定义的限流处理信息......handleException");
    }
}


持久化规则

  • 一旦我们重启应用,sentinel 规则将会消失,所以需要将配置规则进行持久化配置
  • 将限流配置规则持久化进 nacos 保存,需要在 nacos 中手写 JSON 配置,之后刷新 sentinel 控制台即出现配置规则


总结

  • 项目地址
  • 感觉主要针对 sentinel 控制台进行操作,Hystrix 主要通过代码来实现