• sentinel学习笔记


    1. 前言

     

    课前思考:
    1 、当服务访问量达到一定程度,流量扛不住的时候,该如何处理?
    2 、服务之间相互依赖,当服务 A 出现响应时间过长,影响到服务 B 的响应,进而产生连锁反应,直至影响整个依赖链上的
    所有服务,该如何处理?
    这是分布式、微服务开发不可避免的问题。
    1.1 分布式系统遇到的问题
    在一个高度服务化的系统中 , 我们实现的一个业务逻辑通常会依赖多个服务 , 比如 : 商品详情展示服务会依赖商品服务 , 价格
    服务 , 商品评论服务 .
     
    调用三个依赖服务会共享商品详情服务的线程池 . 如果其中的商品评论服务不可用 , 就会出现线程池里所有线程都因等待
    响应而被阻塞 , 从而造成 服务雪崩 . 如图所示 :

    服务雪崩效应:因服务提供者的不可用导致服务调用者的不可用 , 并将不可用逐渐放大的过程,就叫服务雪崩效应
    导致服务不可用的原因: 程序 Bug ,大流量请求,硬件故障,缓存击穿
    大流量请求 】: 在秒杀和大促开始前 , 如果准备不充分 , 瞬间大量请求会造成服务提供者的不可用。
    硬件故障 】: 可能为硬件损坏造成的服务器主机宕机 , 网络硬件故障造成的服务提供者的不可访问。
    缓存击穿 】: 一般发生在缓存应用重启 , 缓存失效时高并发,所有缓存被清空时 , 以及短时间内大量缓存失效时。大量的
    缓存不命中 , 使请求直击后端 , 造成服务提供者超负荷运行 , 引起服务不可用。
    在服务提供者不可用的时候,会出现大量重试的情况:用户重试、代码逻辑重试,这些重试最终导致:进一步加大请求
    流量。所以归根结底导致雪崩效应的最根本原因是:大量请求线程同步等待造成的资源耗尽。当服务调用者使用同步调
    用时 , 会产生大量的等待线程占用系统资源。一旦线程资源被耗尽 , 服务调用者提供的服务也将处于不可用状态 , 于是服务
    雪崩效应产生了。

    1.2 解决方案
    超时机制
    在不做任何处理的情况下,服务提供者不可用会导致消费者请求线程强制等待,而造成系统资源耗尽。加入超时机制,
    一旦超时,就释放资源。由于释放资源速度较快,一定程度上可以抑制资源耗尽的问题。
    服务限流 ( 资源隔离 )
    限制请求核心服务提供者的流量,使大流量拦截在核心服务之外,这样可以更好的保证核心服务提供者不出问题,对于
    一些出问题的服务可以限制流量访问,只分配固定线程资源访问,这样能使整体的资源不至于被出问题的服务耗尽,进
    而整个系统雪崩。那么服务之间怎么限流,怎么资源隔离?例如可以通过线程池 + 队列的方式,通过信号量的方式。
    如下图所示 , 当商品评论服务不可用时 , 即使商品服务独立分配的 20 个线程全部处于同步等待状态 , 也不会影响其他依赖服 务的调用。

     
    服务熔断
    远程服务不稳定或网络抖动时暂时关闭,就叫服务熔断。
    现实世界的断路器大家肯定都很了解,断路器实时监控电路的情况,如果发现电路电流异常,就会跳闸,从而防止电路
    被烧毁。
    软件世界的断路器可以这样理解:实时监测应用,如果发现在一定时间内失败次数 / 失败率达到一定阈值,就 跳闸 ,断路
    器打开 —— 此时,请求直接返回,而不去调用原本调用的逻辑。跳闸一段时间后(例如 10 秒),断路器会进入半开状
    态,这是一个瞬间态,此时允许一次请求调用该调的逻辑,如果成功,则断路器关闭,应用正常调用;如果调用依然不
    成功,断路器继续回到打开状态,过段时间再进入半开状态尝试 —— 通过 跳闸 ,应用可以保护自己,而且避免浪费资
    源;而通过半开的设计,可实现应用的 自我修复
    所以,同样的道理, 当依赖的服务有大量超时时,在让新的请求去访问根本没有意义,只会无畏的消耗现有资源。 比如
    我们设置了超时时间为 1s, 如果短时间内有大量请求在 1s 内都得不到响应,就意味着这个服务出现了异常,此时就没有必 要再让其他的请求去访问这个依赖了,这个时候就应该使用断路器避免资源浪费。

    服务降级
    有服务熔断,必然要有服务降级。
    所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的 fallback (回退)回调,
    返回一个缺省值。 例如: ( 备用接口 / 缓存 /mock 数据 ) 。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当 然这也要看适合的业务场景
     
    2. Sentinel: 分布式系统的流量防卫兵 2.1 Sentinel 是什么
    随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 是面向分布式服务架构的流量控制组件,主要以
    流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定
    性。
    源码地址: https://github.com/alibaba/Sentinel
    官方文档: https://github.com/alibaba/Sentinel/wiki
    Sentinel 具有以下特征 :
    丰富的应用场景 Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控
    制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
    完备的实时监控 Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,
    甚至 500 台以下规模的集群的汇总运行情况。
    广泛的开源生态 Sentinel 提供开箱即用的与其它开源框架 / 库的整合模块,例如与 Spring Cloud Dubbo
    gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel
    完善的 SPI 扩展点 Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。
    例如定制规则管理、适配数据源等。
    阿里云提供了 企业级的 Sentinel 服务, 应用高可用服务 AHAS

     
    2.2.2 Sentinel 工作主流程
    https://github.com/alibaba/Sentinel/wiki/Sentinel%E5%B7%A5%E4%BD%9C%E4%B8%BB%E6%B5%81%E7%A8%8B
    Sentinel 里面,所有的资源都对应一个资源名称( resourceName ),每次资源调用都会创建一个 Entry 对象。 Entry 可以
    通过对主流框架的适配自动创建,也可以通过注解的方式或调用 SphU API 显式创建。 Entry 创建的时候,同时也会创建一
    系列功能插槽( slot chain ),这些插槽有不同的职责,例如 :
    NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来
    限流降级;
    ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这
    些信息将用作为多维度限流,降级的依据;
    StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息;
    FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;
    AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
    DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级;
    SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;

    @SentinelResource 注解实现
    @SentinelResource 注解用来标识资源是否被限流、降级。
    blockHandler: 定义当资源内部发生了 BlockException 应该进入的方法(捕获的是 Sentinel 定义的异常)
    fallback: 定义的是资源内部发生了 Throwable 应该进入的方法
    exceptionsToIgnore :配置 fallback 可以忽略的异常
    源码入口: com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect
    1. 引入依赖
    1 < dependency >
    2 < groupId > com . alibaba . csp groupId >
    3 < artifactId > sentinel annotation aspectj artifactId >
    4 < version > 1.8.0 version >
    5 dependency >
    2. 配置切面支持
    1 @Configuration
    2 public class SentinelAspectConfiguration {
    3
    4 @Bean
    5 public SentinelResourceAspect sentinelResourceAspect () {
    6 return new SentinelResourceAspect ();
    7 }
    8 }
    3. UserController 中编写测试逻辑,添加 @SentinelResource ,并配置 blockHandler fallback
    1 @ RequestMapping ( value = "/findOrderByUserId/{id}" )
    2 @ SentinelResource ( value = "findOrderByUserId" ,
    3 fallback = "fallback" , fallbackClass = ExceptionUtil . class ,
    4 blockHandler = "handleException" , blockHandlerClass = ExceptionUtil . class
    5 )
    6 public R findOrderByUserId ( @ PathVariable ( "id" ) Integer id ) {
    7 //ribbon 实现
    8 String url = "http://mall‐order/order/findOrderByUserId/" + id ;
    9 R result = restTemplate . getForObject ( url , R . class );
    10
    11 if ( id == 4 ){
    12 throw new IllegalArgumentException ( " 非法参数异常 " );
    13 }
    14
    15 return result ;
    16 }
    4. 编写 ExceptionUtil ,注意如果指定了 class ,方法必须是 static 方法
    1 public class ExceptionUtil {
    2
    3 public static R fallback ( Integer id , Throwable e ){
    4 return R . error ( 2 , "=== 被异常降级啦 ===" );
    5 }
    6
    7 public static R handleException ( Integer id , BlockException e ){
    8 return R . error ( 2 , "=== 被限流啦 ===" );
    9 }
    10 }
    5. 流控规则设置可以通过 Sentinel dashboard 配置
    客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。
    1 < dependency >
    2 < groupId > com . alibaba . csp groupId >
    3 < artifactId > sentinel transport simple http artifactId >
    4 < version > 1.8.0 version >
    5 dependency > 6. 启动 Sentinel 控制台
    下载控制台 jar 包并在本地启动:可以参见 此处文档
    1 # 启动控制台命令
    2 java jar sentinel dashboard 1.8.0 . jar
    用户可以通过如下参数进行配置:
    -Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel
    -Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456 ;如果省略这两个参数,默认用户和密码均为
    sentinel
    -Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒; 60m 表示 60 分钟,
    默认为 30 分钟;
    访问 http://localhost:8080/#/login , 默认用户名密码: sentinel/sentinel
    Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包,所以要确保客户端有访问量;

    2.4 Spring Cloud Alibaba 整合 Sentinel
    1. 引入依赖
    1 < dependency >
    2 < groupId > com . alibaba . cloud groupId >
    3 < artifactId > spring cloud starter alibaba sentinel artifactId >
    4 dependency >
    5
    6 < dependency >
    7 < groupId > org . springframework . boot groupId >
    8 < artifactId > spring boot starter actuator artifactId >
    9 dependency >
    2.添加yml配置, 为微服务设置 sentinel 控制台地址
    添加Sentinel后,需要暴露/actuator/sentinel端点,而Springboot默认是没有暴露该端点的,所以需要设置,测试
    http://localhost:8800/actuator/sentinel 1 server :
    2 port : 8800
    3
    4 spring :
    5 application :
    6 name : mall user sentinel demo
    7 cloud :
    8 nacos :
    9 discovery :
    10 server addr : 127.0.0.1 : 8848
    11
    12 sentinel :
    13 transport :
    14 # 添加 sentinel 的控制台地址
    15 dashboard : 127.0.0.1 : 8080
    16 # 指定应用与 Sentinel 控制台交互的端口,应用本地会起一个该端口占用的 HttpServer
    17 # port : 8719
    18
    19 # 暴露 actuator 端点
    20 management :
    21 endpoints :
    22 web :
    23 exposure :
    24 include : '*'
    3.在sentinel控制台中设置流控规则
    资源名 : 接口的 API
    针对来源 : 默认是 default ,当多个微服务都调用这个资源时,可以配置微服务名来对指定的微服务设置阈值
    阈值类型 : 分为 QPS 和线程数 假设阈值为 10
    QPS 类型 : 只得是每秒访问接口的次数 >10 就进行限流
    线程数 : 为接受请求该资源分配的线程数 >10 就进行限流

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

    1.3 流控规则
    流量控制 flow control ),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流
    量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。 同一个资源可以创建多条限流规则。 FlowSlot 会对该资源的所有限流规则依次遍历,直到有规则触发限流
    或者所有规则遍历完毕。一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限
    流效果。
    BlockException异常统一处理
    springwebmvc 接口资源限流入口在 HandlerInterceptor 的实现类 AbstractSentinelInterceptor
    preHandle方法中,对异常的处理是 BlockExceptionHandler 的实现类
    sentinel 1.7.1 引入了 sentinel-spring-webmvc-adapter.jar
    自定义BlockExceptionHandler 的实现类统一处理BlockException
    并发线程数
    并发数控制用于保护业务线程池不被慢调用耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务
    不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致
    线程池耗尽。为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程 池来隔离业务自身之间的资源争抢(线程池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程
    数目太多,线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。 Sentinel 并发控
    制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超
    出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置。

    流控模式
    基于调用关系的流量控制。调用关系包括调用方、被调用方;一个方法可能会调用其它方法,形成一个调用链路的层次关系。
    流控效果
    QPS 超过某个阈值的时候,则采取措施进行流量控制。流量控制的效果包括以下几种: 快速失败(直接 拒绝) Warm Up (预热)、 匀速排队(排队等待) 。对应 FlowRule 中的 controlBehavior 字段。
    快速失败
    RuleConstant.CONTROL_BEHAVIOR_DEFAULT )方式是默认的流量控制方式, QPS 超过任意规则的阈值后,新
    的请求就会被立即拒绝,拒绝方式为抛出 FlowException 这种方式适用于对系统处理能力确切已知的情况
    下,比如通过压测确定了系统的准确水位时。
    Warm Up
    Warm Up RuleConstant.CONTROL_BEHAVIOR_WARM_UP )方式,即预热 / 冷启动方式。当系统长期处于低水位的情
    况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过 " 冷启动 " ,让通过的流量缓
    慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
    冷加载因子 : codeFactor 默认是 3 ,即请求 QPS threshold / 3 开始,经预热时长逐渐升至设定的 QPS
    阈值。
    通常冷启动的过程系统允许通过的 QPS 曲线如下图所示
    匀速排队
    匀速排队(`RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER`)方式会严格控制请求通过的间隔时
    间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
    该方式的作用如下图所示:

    这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
    降级规则
    除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。我们需要对不稳定的弱依赖服务调用 进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
    熔断降级规则说明
    熔断降级规则( DegradeRule )包含下面几个重要的属性:

    熔断策略
    慢调用比例
    慢调用比例 ( SLOW_REQUEST_RATIO ) 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT (即最大的 响应时间),请求的响应时间大于该值则统计为慢调用 当单位统计时长( statIntervalMs )内请求数目大
    于设置的最小请求数目,并且慢调用的比例大于阈值 ,则接下来的熔断时长内请求会自动被熔断。经过熔 断时长后熔断器会进入探测恢复状态(HALF­OPEN 状态),若接下来的一个请求响应时间小于设置的慢 调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
    异常比例
    异常比例 ( ERROR_RATIO ) 当单位统计时长( statIntervalMs )内请求数目大于设置的最小请求数目,并
    且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。 经过熔断时长后熔断器会进入探测恢
    复状态( HALF­OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔
    断。异常比率的阈值范围是 [0.0, 1.0] ,代表 0% ­ 100%
     
    异常数
    异常数 ( ERROR_COUNT ) 当单位统计时长内的异常数目超过阈值之后会自动进行熔断 。经过熔断时长后
    熔断器会进入探测恢复状态( HALF­OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔
    断,否则会再次被熔断。
    注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。
    热点参数限流
    何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
    商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
    用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
    热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。 热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
    系统规则
    Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平
    均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系
    统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
    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 达到阈值即触发系统保护。
    授权控制规则
    很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控
    制(黑白名单控制)的功能。来源访问控制根据资源的请求来源( origin )限制资源是否通过,若配置白名
    单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求
    通过。
    来源访问控制规则( AuthorityRule )非常简单,主要有以下配置项:
    resource :资源名,即限流规则的作用对象。
    limitApp :对应的黑名单 / 白名单,不同 origin , 分隔,如 appA,appB
    strategy :限制模式, AUTHORITY_WHITE 为白名单模式, AUTHORITY_BLACK 为黑名单模式,默认为白名
    单模式。

     

     

     

    滑动时间窗口算法 滑动时间窗口,又称rolling window。为了解决计数器法统计精度太低的问题,引入了滑动窗口 算法。下面这张图,很好地解释了滑动窗口算法:

     

    限流算法小结
    计数器 VS 滑动窗口:
    1 计数器算法是最简单的算法,可以看成是滑动窗口的低精度实现。
    2 滑动窗口由于需要存储多份的计数器(每一个格子存一份),所以滑动窗口在实现上需要更多的存
    储空间。
    3 也就是说,如果滑动窗口的精度越高,需要的存储空间就越大。
    漏桶算法 VS 令牌桶算法:
    1 漏桶算法和令牌桶算法最明显的区别是令牌桶算法允许流量一定程度的突发。
    2 因为默认的令牌桶算法,取走 token 是不需要耗费时间的,也就是说,假设桶内有 100 token 时,
    那么可以瞬间允许 100 个请求通过。
    3 当然我们需要具体情况具体分析,只有最合适的算法,没有最优的算法。
  • 相关阅读:
    包装类与基本类型的区别
    多个PDF发票合并实现一张A4纸打印2张电子/数电发票功能
    机器学习之决策树
    java计算机毕业设计快滴预约平台MyBatis+系统+LW文档+源码+调试部署
    中间件安全: Apache 远程代码执行 (CVE-2021-42013)
    C++智能指针
    Django系列:Django简介与MTV架构体系概述
    Java线程同步:synchronized、Lock锁
    【EI会议征稿】第二届可再生能源与电气科技国际学术会议(ICREET 2023)
    Express操作MongoDB
  • 原文地址:https://blog.csdn.net/chenyong6301567/article/details/126769406