聊聊Sentinel的熔断降级

Posted 又见阿郎

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聊聊Sentinel的熔断降级相关的知识,希望对你有一定的参考价值。

Sentinel的熔断降级实现有两个模式,一开始是基于熔断规则的简单处理(说简单其实不简单),目前已改为了基于断路器模式实现,这也是业内常见实现。

断路器模式

断路器模式中讨论了 3 个主要状态。他们是:

CLOSED
OPEN
HALF OPEN
让我们简要了解一下状态……

CLOSED State
当正在交互的两个服务都启动并运行时,断路器默认关闭。断路器会持续统计远程 API 调用的次数。

OPEN State
一旦远程 API 调用失败百分比超过给定阈值,断路器就会将其状态更改为 OPEN 状态。调用微服务会立即失败,返回异常。也就是说,流量中断了。

HALF OPEN State
在 OPEN 状态停留给定的超时时间后,断路器自动将其状态变为 HALF OPEN 状态。在这种状态下,只允许有限数量的远程 API 调用通过。如果失败调用计数大于此有限数量,则断路器再次变为 OPEN 状态,流量继续中断。否则关闭断路器,流量恢复正常。

流程图可描述如下:

实现

最经典的实现就是Hytrix,而且它的实现是基于响应式编程来做的;其次Spring官方出品的Resilience4j、Sentinel也是基于此方式实现。

Sentinel熔断降级实现关键对象

我个人对Sentinel比较推崇,功能强大,源码易读,而且设计架构简介。Sentinel框架中有三个关键的对象是一直贯彻整个框架的,也是最关键的三个个点:ProcessorSlot、Rule(规则)与指标数据统计(Bucket)。

ProcessorSlot

这里不多讲,实现了责任链模式,基于SPI机制支持可扩展性,这个设计很好,值得借鉴。其实也类似MVC框架的管道模式。DegradeSlot插槽实现断路器模式,最终达到限流降级的目的。

规则与指标数据统计

对于熔断降级或是限流等场景,最后的实现结果一定是由于当前的流量或是异常等维度指标超出了限定值,这个过程就是规则(Rule)的体现,而规则背后的开关实现就是指标数据的统计。这是我个人的理解,大白话表述。

指标数据统计在Sentinel中对应着三个抽象;暂时先不表述。如果要我来实现的话,我的思考是,有一个数据结构存储着在某个时间段内,统计了某些维度的数据(比如成功、异常、总计),而且这个数据结构是随着时间的推移不断地统计;现在给定一个时间点或是时间段,判断是否需要限流或是熔断;在这里就需要注意两个问题点:

  1. 给定的时间是否在统计的时间范围内
  2. 在统计的时间范围内,如果定位到对应的数据结构
指标统计抽象

Sentinel是基于滑动窗口实现资源的实时指标数据统计的。

Sentinel使用Bucket统计一段时间内的各项指标数据,这些指标数据包括请求总数、成功总数、异常总数、总耗时、最小耗时等。一个Bucket可以记录1秒内的数据,也可以记录10毫秒内的数据,这由采样周期决定。采样周期就是每个Bucket的时间窗口大小。

WindowWrap,用于记录Bucket的时间窗口信息(包括时间窗口的开始时间戳和大小),而WindowWrap数组就是一个滑动窗口。当收到一个请求时,可以根据收到请求时的时间戳和滑动窗口大小计算出一个索引值,从滑动窗口(WindowWrap数组)中获取一个WindowWrap类,从而获取WindowWrap类包装的Bucket,并调用Bucket实例的add方法统计指标。

LeapArray,Sentinel 中统计指标的基本数据结构。基于滑动窗口算法来计算数据返回windowWrap时间窗口对象。前面说的两个问题在这个数据结构里面都有对应的算法实现,当然还有别的统计算法,但最后都是算时间窗口。

脑图概览

SpringCloud Alibaba——Sentinel服务熔断与限流(二降级规则)

1.开篇

上一篇文章说完了sentinel的流控规则,其中包括流控模式(直接、关联、链路)、流控效果(快速失败、预热、排队等待)。

更详细的内容可以参考:https://szh-forever-young.blog.csdn.net/article/details/119568801

这篇文章再来聊聊sentinel的降级规则。官方文档:https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7

这三种降级规则分别是:RT、异常比例、异常数。

  • RT(平均响应时间,秒级)

           平均响应时间   超出阈值  且   在时间窗口内通过的请求>=5,两个条件同时满足后触发降级。窗口期过后关闭断路器。
           RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)

  • 异常比列(秒级)

            QPS >= 5 且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级。

  • 异常数(分钟级)

             异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级。

这里需要注意:之前SpringCloud H版中的Hystrix服务熔断降级中是有半开状态的;而SpringCloud Alibaba的Sentinel的断路器是没有半开状态的,通俗来说,你的保险丝要么是断开,要么就闭合。


2.项目源码

github源码地址:https://github.com/2656307671/SpringCloud-Alibaba-Sentinel

gitee源码地址:https://gitee.com/szh-forever-young/SpringCloud-Alibaba-Sentinel

本次做Sentinel测试的代码请参考上面的仓库。

2.1 RT

我们在sentinel的界面中来配置RT。

首先设置RT的阈值为200ms,是说testD的请求必须在200ms内完成,如果无法完成,则在未来的1秒内将进行服务熔断降级;1秒持续进入5个请求是默认的。

之后在Postman中,设置testD这个请求,永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,如果超过200毫秒还没处理完(代码中每个testD请求都会sleep 1秒),在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了。后续Postman中的Run停止了,访问量逐渐减少了,再次访问testD可以看到恢复正常了。

2.2 异常比例

这里我们设置了异常比例是0.2,即20%。如果出错,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了。

对应代码中的testE请求。其中有一行:int age = 10/0; 这明显是一个运行时异常。但是我们在Postman中设置了访问10次testE;直接高并发发送请求,多次调用达到我们的异常比例配置条件了。因为一出现异常,那异常比例就是100%啊,所以此时不再报错error而是服务降级了。

不使用Postman,直接访问了话,则会报error,此时与服务降级就无关了。单独访问一次,必然来一次报错一次(int age  = 10/0),调一次错一次;

2.3 异常数

首先异常数是按分钟来统计的。这里对应代码中的testF请求方法。

这里设置的意思是:当异常数达到5次的时候,就会进行服务熔断降级,也即看到的是sentinel默认的出错页面信息,而不是error page。

以上是关于聊聊Sentinel的熔断降级的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud Alibaba——Sentinel服务熔断与限流(二降级规则)

SpringCloud Alibaba——Sentinel服务熔断与限流(二降级规则)

聊聊因不恰当使用alibaba sentinel而踩到的坑

sentinel 熔断降级

SpringCloud Alibaba——Sentinel服务熔断与限流(五服务熔断)

SpringCloud Alibaba——Sentinel服务熔断与限流(五服务熔断)