Sentinel 研究手册
为什么需要流量控制?
首先明确一个概念:
服务雪崩
:由于某个微小的服务挂了,导致整一大片的服务都不可用。
举个例子:
在一个微服务架构模式下的系统当中,会存在很多个服务,这些服务彼此之间或多或少会存在调用关系。假设服务A1调用了服务B1,服务B又调用了服务C1。在服务C1由于某种原因,出现了阻塞,然后服务B1、A1都在等待C1的响应结果。此时如果在没有感知到这三个节点的状态的情况下,又恰好有许多请求转发到了C1上,使得C1出现了过载现象
雪崩发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方法响应变慢,亦或是某台机器的资源耗尽。我们无法完全杜绝雪崩源头的发生,只有做好足够的容错,保证在一个服务发生问题,不会影响到其它服务的正常运行。因此,我们需要引入一种机制,对服务质量进行监控。如果哪个节点中出现了服务不可用或者是响应缓慢时,我们就减少对其调用的频率,将其工作任务转发给当前节点所在服务集群的其他节点进行处理。过一段时间后再逐渐恢复对其的调用。
服务雪崩的常见解决方案
要防止雪崩的扩散,我们就要做好服务的容错。常见的容错思路有隔离、超时、限流、熔断、降级这几种。
隔离机制
在上游服务调用多个下游服务的时候,给不同的下游服务分配固定的线程——不会把所有的线程都分配给某一个服务。
例如:服务A内总共有100个线程,现在服务A可能会调用服务B、服务C、服务D。隔离策略:调用服务B分配30个线程;调用服务C分配30个线程;调用服务D分配40个线程。这样进行资源的隔离,保证即使下游某个服务挂了,也不至于把服务A的线程消耗完。
超时机制
在上游服务调用下游服务的时候,设置一个最大响应时间,如果超过这个时间,下游未作出反应,就断开请求,释放掉线程。
限流机制
限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。
熔断机制
在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。
服务熔断一般有三种状态:
- 熔断关闭状态(Closed):服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制。
- 熔断开启状态(Open):后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法。
- 半熔断状态(Half-Open):尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断关闭状态。
Sentinel的介绍
Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。
Sentinel 分为两个部分:
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
Sentinel与其他类似组件比较
Sentinel | Hystrix | Resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发线程数限流) | 线程池隔离/信号量隔离 | 信号量隔离 |
熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 | 基于异常比率、响应时间 |
实时统计实现 | 滑动窗口(Leaparray) | 滑动窗口(基于 RxJava) | Ring Bit Buffer |
动态规则配置 | 支持多种数据源 | 支持多种数据源 | 有限支持 |
扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
限流 | 基于QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 | 简单的 Rate Limiter 模式 |
系统自适应保护 | 支持 | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 | 不提供控制台,,可对接其他监控系统 |
Sentinel的相关概念
资源(Resource)
在Sentinel参与到的系统当中,一切皆可视为资源。
资源可以是一段代码,又或者是一个接口,Sentinel中并没有什么强制规定,但是实际项目中一般以一个接口为一个资源,比如说一个http接口,又或者是rpc接口,它们就是资源,可以被保护。
资源是通过Sentinel的API定义的,每个资源都有一个对应的名称,比如对于一个http接口资源来说,Sentinel默认的资源名称就是请求路径。
Sentinel可以视为保护资源的卫兵。
说明:
- “资源”在一个系统中是唯一的吗?即不同接口上的资源名称可以重复吗?
答:可以重复。resource相当于是一个分类,可以加在不同的接口上。 - 一个资源名称,在两个接口上一起使用时,限流统计规则是两个接口独立计算。
- 资源定义的方式有很多种,建议通过注解。
规则(Rules)
规则也是一个重要的概念,规则其实比较好理解,比如说要对一个资源进行限流,那么限流的条件就是规则,后面在限流的时候会基于这个规则来判定是否需要限流。
Sentinel的规则分为流量控制规则、熔断降级规则以及系统保护规则,不同的规则实现的效果不一样。
流量控制
这里的流量控制指的是对各个服务节点网络访问请求的控制,根据服务节点的处理能力,动态地调整访问流量阈值。
流量控制有以下几个角度:
- 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
- 运行指标,例如 QPS、线程池、系统负载等;
- 控制的效果,例如直接限流、冷启动、排队等。
服务熔断、服务降级和服务限流
熔断降级是防止出现服务雪崩而采取的一种措施。当一个节点堆积了许多未来的及处理的请求时,就会发生频繁超时、异常比例升高。因此需要感知服务调用状态,当出现这中现象时,再有服务请求要访问这个节点,就阻止访问,直接返回调用失败的提示,释放资源。然后再隔一段时间后又慢慢地尝试恢复对其访问,测试其有没有恢复,如果恢复,则恢复对其的正常访问。这便是服务熔断
。它在服务调用方直接阻止了对服务的调用。
服务降级
则是相对于被访问节点而言。当这个节点面对大量的服务请求处理的力不从心是,果断放弃当前节点中的边缘业务,留下资源,用于处理核心业务。当发生对边缘业务的处理请求时,不做真正的业务处理,直接返回一个友好的提示,释放资源,从而保证对核心业务的处理能力。
服务限流
则对访问当前节点的请求数直接做出限定,比如规定1秒内,只能有100请求访问当前节点,则第101个服务请求在这一秒内来访问的话,会被直接给拒绝掉。
Sentinel在当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时,对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。
服务熔断作用于服务调用方(服务上游),服务降级作用于服务提供方(服务下游)
Sentinel如何实现熔断降级
限制资源并发线程的数量
优点:没有线程切换的损耗,也不需要预先分配线程池的大小。
说明:当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
通过响应时间对资源进行降级
说明:当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
Sentinel核心类
Entry
每一次资源调用都会创建一个 Entry
。
Entry
中持有本次对资源调用的相关信息:
- createTime:创建该Entry的时间戳。
- ProcessorSlot链
- curNode:Entry当前是在哪个节点。
- orginNode:Entry的调用源节点。
- resourceWrapper:Entry关联的资源信息。
- 任何一个被保护的资源都被封装成
resourceWrapper
对象
- 任何一个被保护的资源都被封装成
Entry
是一个抽象类,CtEntry
是 Entry
的实现,CtEntry
持有Context和调用链的信息。
1 | //代表要处理名称为HelloWorld的资源。操作成功后会返回一个Entry对象,否则抛出异常代表不处理当前请求(可以认为是规则限制) |
Sphu.entry
SphU.entry()通过一系列的调用最终调用到CtSph的entryWithPriority()方法上:
1 | //resourceWrapper:是StringResourceWrapper对象,表示资源 |
说明:创建完Context对象后,使用SPI构建slot链,之后是创建Entry对象,之后就是遍历slot链以决定是否允许该请求访问资源。
需要注意的一点:CtEntry 构造函数中会做调用链的变换,即将当前 Entry 接到传入 Context 的调用链路上(setUpEntryFor
)。
资源调用结束时需要 entry.exit()
。exit 操作会过一遍 slot chain exit,恢复调用栈,exit context 然后清空 entry 中的 context 防止重复调用。
Context
Context 代表调用链路上下文,贯穿一次调用链路中的所有 Entry
。Context 维持着入口节点(entranceNode
)、本次调用链路的 curNode、调用来源(origin
)等信息。Context保存在ThreadLocal中。
Context可以在资源调用之前手动通过ContextUtil.enter(name,origin)创建,name为当前context的名称,origin为调用方名称,当配置了调用方限流的时候会用到。
1 | //name表示Context的名称或者链路入口的名称,origin表示调用来源的名称,默认为空字符串 |
初始化
在初始化slot责任链部分前,执行context的初始化。在Context初始化的过程中,会把EntranceNode加入到Root子节点中(实际Root本身是一个特殊的EntranceNode),并把EntranceNode放到contextNameNodeMap中。
1 | root |
每调用一次SphU.entry()方法都会在访问链路树上增加一个子节点,通过这个树可以还原出资源的访问路径。
每访问一个资源,Context对象都使用curEntry属性记录下正在访问资源对应的Entry对象,Entry对象有一个parent属性记录下父Entry,比如上面代码中,nodeB的父Entry是nodeA,Entry还有一个curNode属性,该属性记录了对应的DefaultNode对象。每个DefaultNode对象还有一个ClusterNode类的属性clusterNode,clusterNode的作用是记录被访问的资源的统计数据,比如平均响应时间、总请求数、QPS等,FlowSlot便是依据这些数据来判断是否允许访问资源。Context可以通过上述这些属性构建出一个完整的资源访问树,并将资源访问数据更新到对应的ClusterNode对象中。
维持方式
通过 ThreadLocal 传递,只有在入口 enter
的时候生效。由于 Context 是通过 ThreadLocal 传递的,因此对于异步调用链路,线程切换的时候会丢掉 Context,因此需要手动通过 ContextUtil.runOnContext(context, f)
来变换 context。
Node
Node中保存了对资源的实时数据的统计,Sentinel中的限流或者降级等功能就是通过Node中的数据进行判断的。Node是一个接口,里面定义了各种操作request、exception、rt、qps、thread的方法。
Sentinel 里面的各种种类的统计节点:
StatisticNode
:最为基础的统计节点,包含秒级和分钟级两个滑动窗口结构。用于完成数据统计。DefaultNode
:默认节点,用于统计一个资源在当前Context中的流量数据。ClusterNode
:集群节点,用于统计一个资源在所有Context中的总体流量数据。EntranceNode
:入口节点,特殊的链路节点,对应某个 Context 入口的所有调用数据,创建维度为resource。Constants.ROOT
节点也是入口节点。
构建的时机:
EntranceNode
在ContextUtil.enter(xxx)
的时候就创建了,然后塞到 Context 里面。NodeSelectorSlot
:根据 context 创建DefaultNode
,然后 set curNode to context。ClusterBuilderSlot
:首先根据 resourceName 创建ClusterNode
,并且 set clusterNode to defaultNode;然后再根据 origin 创建来源节点(类型为StatisticNode
),并且 set originNode to curEntry。
几种 Node 的维度(数目):
ClusterNode
的维度是 resourceDefaultNode
的维度是 resource * context,存在每个 NodeSelectorSlot 的map
里面EntranceNode
的维度是 context,存在 ContextUtil 类的contextNameNodeMap
里面- 来源节点(类型为
StatisticNode
)的维度是 resource * origin,存在每个 ClusterNode 的originCountMap
里面
Slot Chain
sentinel在内部创建了一个责任链,责任链是由一系列Processor Slot对象组成的,每个Processor Slot对象负责不同的功能,外部请求是否允许访问资源,需要通过责任链的校验,只有校验通过的,才可以访问资源,如果被校验失败,会抛出BlockException异常。
辅助资源指标数据统计的Process Slot
:
NodeSelectorSlot
负责收集资源路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级、数据统计。ClusterBuilderSlot
建ClusterNode对象,该对象用于统计访问资源的QPS、线程数、异常、响应时间等,每个资源对应一个ClusterNode对象。StatisticSlot
用于从多个维度(入口流量、调用者、当前被访问资源)统计响应时间、并发线程数、处理失败个数、处理成功个数等。核心的SlotFlowSlot
用于流控,可以根据QPS或者每秒并发线程数控制,当QPS或者并发线程数超过设定值,便会抛出FlowException异常。FlowSlot依赖于StatisticSlot的统计数据。
这些辅助ProcessorSlot需要严格的顺序执行
NodeSelectorSlot ——> ClusterBuilderSlot ——> StatisticSlot
实现降级功能的Process Slot
:
AuthoritySlot
黑白名单校验,按照字符串匹配,如果在黑名单,则禁止访问。DegradeSlot
用于服务降级,如果发现服务超时次数或者报错次数超过限制,DegradeSlot将禁止再次访问服务,等待一段时间后,DegradeSlot试探性的放过一个请求,然后根据该请求的处理情况,决定是否再次降级。SystemSlot
校验QPS、并发线程数、系统负载、CPU使用率、平均响应时间是否超过限制,使用滑动窗口算法统计上述这些数据。LogSlot
打印日志。
总体的框架如下:
详细说明:
自定义slot
我们也可以添加自定义的slot,只需要实现ProcessorSlot接口,在com.alibaba.csp.sentinel.slotchain.ProcessorSlot文件中添加自定义类的全限定名,然后使用注解@SpiOrder
指定顺序即可。
StatisticSlot
StatisticSlot
是 Sentinel 最为重要的类之一,用于根据规则判断结果进行相应的统计操作。
entry 的时候:依次执行后面的判断 slot。每个 slot 触发流控的话会抛出异常(BlockException
的子类)。若有 BlockException
抛出,则记录 block 数据;若无异常抛出则算作可通过(pass),记录 pass 数据。
exit 的时候:若无 error(无论是业务异常还是流控异常),记录 complete(success)以及 RT,线程数-1。
记录数据的维度:线程数+1、记录当前 DefaultNode 数据、记录对应的 originNode 数据(若存在 origin)、累计 IN 统计数据(若流量类型为 IN)。
Process Slot Chain
Sentinel 的核心骨架,将不同的 Slot 按照顺序串在一起(责任链模式),从而将不同的功能(限流、降级、系统保护)组合在一起。
Sentinel 会为每个资源创建且仅创建一个 ProcessorSlotChain,只要名称相同就认为是同一个资源。ProcessorSlotChain 被缓存在 CtSph.chainMap 静态字段,key 为资源 ID.
SPI 扩展
Sentinel 提供多样化的 SPI 接口用于提供扩展的能力。开发者可以在用同一个 sentinel-core
的基础上自行扩展接口实现,从而可以方便地根据业务需求给 Sentinel 添加自定义的逻辑。目前 Sentinel 提供如下的扩展点:
- 初始化过程扩展:提供
InitFunc
SPI接口,可以添加自定义的一些初始化逻辑,如动态规则源注册等。 - Slot/Slot Chain 扩展:用于给 Sentinel 功能链添加自定义的功能并自由编排。
- 指标统计扩展(StatisticSlot Callback):用于扩展 StatisticSlot 指标统计相关的逻辑。
- Transport 扩展:提供 CommandHandler、CommandCenter 等接口,用于对心跳发送、监控 API Server 进行扩展。
- 集群流控扩展:可以方便地定制 token client/server 自定义实现,可参考对应文档
- 日志扩展:用于自定义 record log Logger,可用于对接 slf4j 等标准日志实现。
Sentinel部署k8s
sentinel docker镜像化
windows系统下载一个Docker Desktop。
下载sentinel-dashboard.jar
https://github.com/alibaba/Sentinel/releases最新版本为:1.8.6
编写Dockerfile
1
2
3
4
5
6
7
8FROM openjdk:8-jre-slim
COPY sentinel-dashboard-1.8.6.jar sentinel-dashboard.jar
ENV JAVA_OPTS="-Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard"
ENTRYPOINT java ${JAVA_OPTS} -jar sentinel-dashboard.jar
此处需要注意的是:版本号一致;1.8.6版本的默认端口号为8080
将jar包和Dockerfile放到同一目录,执行打包命令
1 | docker build -t sentinel/sentinel-dashboard:1.8.6 -f Dockerfile . |
说明:
1 | docker build -t ImageName:TagName dir |
给镜像打个标签
1
docker tag sentinel-dashboard:1.8.6 10.99.180.131/jxcccommon/jxcc-sentinel:1.0
说明:标签类似于版本
本地测试镜像是否正常运行
1
docker run --name sentinel -p 8080:8080 -td 10.99.180.131/jxcccommon/jxcc-sentinel:1.0
访问localhost:8080
登录10.99.180.131 harbor.jxcc.com,需要输入用户名密码
此处可以上传到docker-hub仓库。
上传镜像到harbor仓库
1
docker push 10.99.180.131/jxcccommon/jxcc-sentinel:1.0
k8s容器化部署
- 创建工作负载;确定好pull的镜像地址和内部容器端口号
- 创建服务;选择1中创建的工作负载
- 启动服务
方案选择
方案一:微服务单独集成sentinel
将 Sentinel 集成到单个微服务的优缺点:
优点:
- 隔离性: 在每个微服务中集成 Sentinel 可以实现更细粒度的流量控制和熔断策略,使得每个微服务可以根据自身特点和需求进行配置。
- 更灵活的限流策略: 每个微服务可以根据自己的业务场景定制限流策略,避免不同微服务之间的相互影响。
- 独立运维: 每个微服务独立配置 Sentinel,减少了对网关的依赖,即使网关出现问题也不会影响到其他微服务。
缺点:
- 配置重复: 如果有多个微服务,可能需要在每个微服务中都配置 Sentinel 规则,导致配置重复和维护成本增加。
- 监控分散: 每个微服务的监控数据被分散到各个微服务中,可能需要额外的工作来汇总和分析监控数据。
方案二:gateway集成sentinel
相较于单独使用sentinel,其优点在于:
统一的监控:Gateway集成Sentinel后,可以将所有微服务的请求都通过Gateway进行转发,这样可以更方便地对所有请求进行统一的监控和管理,从而实现更全面、更深入的监控。
更高的可靠性:Gateway集成Sentinel后,可以在网关层面对请求进行限流和熔断,从而保证微服务的可靠性和稳定性。而如果单独使用Sentinel,可能需要在每个微服务中都进行限流和熔断的配置,这样会增加配置的复杂度和维护的难度。
更好的灵活性:Gateway集成Sentinel后,可以根据不同的业务场景和需求,灵活地配置限流和熔断规则,从而更好地满足不同的业务需求。而如果单独使用Sentinel,可能需要在每个微服务中都进行限流和熔断的配置,这样会限制配置的灵活性。
更好的性能:Gateway集成Sentinel后,可以在网关层面对请求进行限流和熔断,从而减少了微服务的请求压力,提高了系统的性能和响应速度。而如果单独使用Sentinel,可能需要在每个微服务中都进行限流和熔断的配置,这样会增加系统的负担,降低系统的性能。
缺点:
- 单点故障: 如果网关本身出现故障,整个微服务架构的流量控制和熔断功能可能会受到影响。
- 性能瓶颈: 将流量控制和监控逻辑集中在网关中可能增加网关的负载,需要进行适当的性能测试和优化。
访问地址:10.99.186.32:31783
控制台和客户端通信原理
控制台的使用
控制台使用懒加载,在第一次访问的时候才会开始进行初始化,并向控制台发送心跳和客户端规则等信息。
交互方式
- 首先 sentinel-core 向 dashboard 发送心跳包
- dashboard 将 sentinel-core 的机器信息保存在内存中
- dashboard 根据 sentinel-core 的机器信息通过 httpClient 获取实时的数据
- sentinel-core 接收到请求之后,会找到具体的 CommandHandler 来处理
- sentinel-core 将处理好的结果返回给 dashboard
连接 dashboard
sentinel-core 在初始化的时候,通过 JVM 参数中指定的 dashboard 的 ip 和 port,会主动向 dashboard 发起连接的请求,该请求是通过 HeartbeatSender 接口以心跳的方式发送的,并将自己的 ip 和 port 告知 dashboard。这里 sentinel-core 上报给 dashboard 的端口是 sentinel 对外暴露的自己的 CommandCenter 的端口。
HeartbeatSender 有两个实现类,一个是通过 http,另一个是通过 netty。
该类通过一个 HttpClient 向 dashboard 发送了自己的信息,包括 ip port 和版本号等信息。
其中 consoleHost 和 consolePort 的值就是从 JVM 参数 csp.sentinel.dashboard.server 中获取的。
dashboard 在接收到 sentinel-core 的连接之后,就会与 sentinel-core 建立连接,并将 sentinel-core 上报的 ip 和 port 的信息包装成一个 MachineInfo 对象,然后通过 SimpleMachineDiscovery 将该对象保存在一个 map 中,如下图所示:
请求数据
当 dashboard 有了具体的 sentinel-core 实例的 ip 和 port 之后,就可以去请求所需要的数据了。
当在页面上查询某一台机器的限流的规则时,是将该机器的 ip 和 port 以及 appName 都传给了服务端,服务端通过这些信息去具体的远程实例中请求所需的数据,拿到数据后再封装成 dashboard 所需的格式返回给前端页面进行展示。
客户端
sentinel-core 在启动的时候,执行了一个 InitExecutor.init 的方法,该方法会触发所有 InitFunc 实现类的 init 方法。
因为这里我们引入了sentinel-transport-simple-http
模块,所以使用spi加载InitFunc的子类的时候会新加载两个子类实例,分别是:CommandCenterInitFunc、HeartbeatSenderInitFunc。然后会遍历loader,根据@InitOrder的大小进行排序,并封装成OrderWrapper放入到initList中。
CommandCenterInitFunc 则会启动一个 CommandCenter 对外提供 sentinel-core 的数据服务,而这些数据服务是通过一个一个的 CommandHandler 来提供的
Sentinel 控制台、Nacos 和客户端应用程序之间的交互过程
- 配置规则: 在 Sentinel 控制台中配置流控、降级等规则,输入资源名、限流参数、策略等信息,并保存配置。
- 推送配置到 Nacos: Sentinel 控制台会将配置的规则信息推送到 Nacos 配置中心。这需要在 Nacos 上创建相应的配置项。
- 客户端应用程序从 Nacos 拉取配置: 客户端应用程序通过 Nacos 的配置监听机制,定时或实时地从 Nacos 中拉取最新的规则配置信息。
- 解析规则: 客户端应用程序将从 Nacos 拉取的规则配置进行解析,转换为内部的规则对象。
- 注册规则: 客户端应用程序将解析后的规则注册到 Sentinel 中的规则管理模块。
- 实时监控和限流处理: 客户端应用程序在运行时实时监控流量情况,根据规则配置进行限流、降级等操作。当请求达到限流条件时,Sentinel 会根据规则进行相应的限流处理。
- 动态刷新: 如果在 Sentinel 控制台上更新了规则,控制台会将新的规则配置推送到 Nacos 配置中心。客户端应用程序通过 Nacos 配置监听机制感知配置变更并获取到最新的规则配置,然后进行动态刷新。
- 实时监控与反馈: Sentinel 控制台提供实时的监控界面,您可以在控制台上查看应用程序的流量、规则生效情况等数据,以及对异常情况进行相应的处理。
sentinel执行规则
Sentinel 执行规则的过程是基于 AOP(面向切面编程)和动态代理的机制。当应用程序的资源被访问时,Sentinel 会拦截这些访问,根据事先配置的规则进行判断和处理,从而实现流量控制、降级等功能。以下是 Sentinel 如何执行规则的一般流程:
- 定义资源: 在应用程序中,您需要定义要受到限流、降级等规则控制的资源,比如方法、API、URL 等。
- 规则配置: 使用 Sentinel 控制台或通过代码方式,在规则管理中配置资源对应的限流、降级等规则,定义规则的类型、条件、策略等信息。
- 切入点拦截: Sentinel 使用 AOP 技术拦截您定义的资源访问切入点。这意味着当应用程序的资源被访问时,Sentinel 会拦截这些访问并进行处理。
- 规则匹配: Sentinel 根据请求的资源信息,匹配事先配置的规则,判断请求是否满足规则条件,如是否超出了限流阈值。
- 限流处理: 如果请求满足规则条件,Sentinel 将执行规则配置中指定的限流策略,比如拒绝请求、返回预设错误信息等。
- 降级处理: 如果资源的请求达到降级条件,Sentinel 将执行降级策略,返回降级后的响应,避免影响系统的整体稳定性。
- 统计和监控: Sentinel 会根据请求的情况进行统计,生成流量、规则生效情况等监控数据,供您在 Sentinel 控制台上查看。
- 动态刷新: Sentinel 允许您在运行时动态调整规则配置,从而实现灵活的流量控制和降级策略。
总体而言,Sentinel 在应用程序运行时,通过拦截资源的访问切入点,根据预先配置的规则进行匹配和处理,从而实现流量控制、降级等功能。
问题
问题一:sentinel熔断降级与自定义异常拦截冲突
项目中使用了自定义全局异常处理,而异常数或者异常比例的统计在
1 | com.alibaba.csp.sentinel.adapter.spring.webmvc.AbstractSentinelInterceptor.afterCompletion |
这个方法执行,自定义全局异常的处理会先于
1 | com.alibaba.csp.sentinel.adapter.spring.webmvc.AbstractSentinelInterceptor.afterCompletion |
这个方法执行执行,因为我们在全局异常里面已经对异常进行处理,比如转换为一个对象,这样导致AbstractSentinelInterceptor.afterCompletion无法获取到异常,进而无法统计异常数或者异常比例。
解决办法
全局异常修改:
1、引入jar包
1 | <dependency> |
2、在@ExceptionHandler方法中使用Tracer.trace(e)方法将异常信息传递给Sentinel进行统计
1 | /** |
问题二:热点规则不生效
web埋点如果以url作为资源名,规则不生效
解决方法
注意是否使用了@SentinelResource注解定义的name作为资源名
配置热点规则配置@SentinelResource后,可能还会出现
1
java.lang.reflect.UndeclaredThrowableException: null
需要在方法中添加throws BlockException或添加blockHandler来处理异常