Sentinel核心源码分析(上)

文章目录


前言

  Sentinel作为Spring cloud alibaba中流控的组件,在微服务架构中也有广泛的应用。其核心源码主要体现在客户端。客户端在启动时,和Nacos类似,也会将自己的信息注册到服务端。而服务端的页面上配置各种规则时,实际上也是将信息发送到了客户端。

  我们最常使用的@SentinelResource注解:

  底层也是基于AOP + 责任链模式实现的。**Sentinel的难点不在于处理流程,而在于限流的算法。**本篇仅介绍Sentinel责任链的核心流程。


一、客户端与Spring Boot整合

  在Spring Boot项目中,如果需要引入Sentinel,通常需要在pom文件中加入:

xml 复制代码
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

  该组件也是利用了Spring Boot的自动配置:

  其中的SentinelAutoConfiguration是核心:

  在SentinelAutoConfiguration中,会注册SentinelResourceAspect Bean:

  SentinelResourceAspect实际上是一个切面,匹配了所有加入了@SentinelResource注解的方法:

  invokeResourceWithSentinel是一个环绕通知。 。在执行目标方法之前,首先会得到目标方法对象,以及处理注解中的一些信息,然后调用SphU.entry方法。该方法是Sentinel流程的核心。

  点击进去,会调用到entry方法:

  Env在实例化之前,会触发static中的逻辑:

  在doInit方法中,又会通过SPI机制,加载InitFunc中的类:

  其中的HeartbeatSenderInitFunc是定期向服务端发送心跳的:

  CommandCenterInitFunc,是将客户端各种接收规则的接口信息,暴露给服务端:

  上面的逻辑,包括后续构建,执行责任链,是在切面中,并非是在应用启动时执行的,而是在执行加入了@SentinelResource注解的方法时才会去执行!

二、SphU.entry

  SphU.entry方法内部主要做了两件事:

  • 构建责任链。
  • 按照顺序依次调用责任链。

2.1、构建责任链

  在进入lookProcessChain方法后,首先通过双检锁模式,判断当前加入了@SentinelResource注解的方法,是否已经为其构建过责任链,如果没有,才会执行newSlotChain方法。也就是说,是每一个加入了注解的方法,都有一个对应的责任链,并且只在应用启动后该方法第一次被调用时初始化。

  最终调用的是DefaultSlotChainBuilder的build方法:

  在该方法中,主要做了两件事:

  通过SPI机制,加载ProcessorSlots文件中的类(责任链中的具体组成类)。

  真正地去构建责任链:在执行ProcessorSlotChain chain = new DefaultProcessorSlotChain();这一段代码时,实际上是构造了:

  构造出的是下图的数据结构,end是指向first的引用:

  在构造完成后,就会利用chain.addLast((AbstractLinkedProcessorSlot<?>) slot);方法,向上图的数据结构中插入具体的责任链类了:

  首先将end的next指针指向NodeSelectorSlot,因为end是指向指向first的引用,实际上first的next指针也指向了NodeSelectorSlot:

  然后将end指向NodeSelectorSlot:

  以此类推,最终构建出的责任链是:

图片来源:图灵学院

2.2、调用责任链

  这里我们重点关注FlowSlot和DegradeSlot,它们是sentinel核心功能-限流熔断降级的体现。

2.2.1、NodeSelectorSlot

  首先调用的是NodeSelectorSlot,它的作用是构建资源调用的统计节点,用于记录调用链路信息,并且将资源关联到相应的 DefaultNode。

  fireEntry就是在满足条件的情况下,继续调用后续的责任链。

2.2.2、ClusterBuilderSlot

  ClusterBuilderSlot和NodeSelectorSlot是类似的,它的作用是构建统计节点的聚合关系。但是NodeSelectorSlot 是按调用链统计,ClusterBuilderSlot 是按资源维度统计。

2.2.3、LogSlot

  LogSlot的作用,是在后续的责任链调用过程中出现异常时,进行日志的记录,体现在它的try...catch中:

2.2.4、StatisticSlot

  StatisticSlot是先将请求放行到后续的责任链,在后续的责任链调用完成后,再去进行统计资源的调用情况的操作。例如记录 QPS(每秒请求数)、RT(响应时间)、线程数、异常数等。

  包括抛出了各种异常之后的记录,这些记录都是执行降级、限流等控制的基础数据来源。

2.2.5、AuthoritySlot

  AuthoritySlot是进行授权规则的检查,例如黑白名单:


  简单回顾一下黑白名单的使用,首先需要在sentinel控制台的授权规则选项卡进行配置:

  这里的资源名,是http请求的路径,而流控应用,可以是特定的ip,也可以是请求路径:

java 复制代码
@Component
public class IPLimiter implements RequestOriginParser {

	/**
	*	获取当前服务实例的ip
	*/
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        return httpServletRequest.getRemoteAddr();
    }
}

  在checkBlackWhiteAuthority方法中,首先会获取所有设置的规则,然后根据当前的资源名,获取该资源对应的所有规则

  然后进行检查:

  这里的黑白名单体现在RuleConstant这个常量类中:

  判断逻辑有点绕:

  • 如果规则中的IP或路径,和请求中的匹配,contain会为true,反之为false。
  • 在黑名单的判定中,如果contain为true,则返回false,代表请求不通过。因为黑名单就是要对能和规则匹配上的请求进行拦截。
  • 在白名单的判断中,如果contain为false,则返回false,代表请求不通过。因为contain为false,代表请求和规则匹配不上,也就是不在白名单中。

2.2.6、SystemSlot

  SystemSlot是对系统规则进行控制,包括系统整体的 QPS,平均响应时间(RT),当前系统的并发线程数等。

2.2.7、FlowSlot

  FlowSlot是 Sentinel 的核心功能之一,用于流量控制(限流)规则判断。

  同样会获取到控制台设置的所有规则,然后逐个进行匹配:

  最终调用到的是passLocalCheck,其中也有两个关键方法:

2.2.7.1、selectNodeByRequesterAndStrategy

  selectNodeByRequesterAndStrategy用于在执行限流时 选择哪个节点(Node)来做统计和判断。不同的来源(origin)和限流策略(strategy)决定了限流数据统计的维度。首先会获取到流控模式,也就是控制台设置的:

  • 匹配指定 origin 的限流
    • 如果是直接模式,就利用context.getOriginNode(); 调用方自己的统计节点限流。
    • 如果是其他策略,利用selectReferenceNode再次匹配:
  • 如果来源是default:
    • 直接限流时,使用当前资源的全局统计节点
    • 非直接限流,使用关联资源的统计节点。
  • 如果来源是other:
    • 直接限流时,使用当前资源的全局统计节点
    • 非直接限流,使用关联资源的统计节点。
2.2.7.2、canPass

  在拿到上一步推断出的节点后,会调用canPass方法,这里的canPass也有不同的实现:

  对应控制台中的:

  这里涉及到滑动窗口,令牌桶,漏桶算法,会在后续进行说明。 Sentinel的难点不在于流程,而是算法。

2.2.8、DegradeSlot

  DegradeSlot的作用是熔断降级控制。也是 Sentinel 的核心功能之一:

  在tryPass方法中,会对逐条规则进行校验,如果此时的断路器处于打开状态,

  并且超过了熔断时间,会修改状态为半开。

  熔断降级中有一个重要的概念,也就是断路器。在Sentinel 1.8 版本之后,断路器有三种状态,都记录在CircuitBreaker的内部State枚举类中:

  在这里简单的说一下三种状态的转换:

  1. 正常情况下,断路器处于关闭状态,所有请求正常通过。
  2. 当请求触发了降级条件(如异常比例过高、RT过大) 后,断路器会进入打开状态,在接下来的熔断时长内(如 10 秒),所有请求都被拒绝(降级)。
  3. 当熔断时长结束后,下一个请求到达时,断路器进入半开状态:
    • 如果该请求再次触发降级条件,断路器重新回到打开状态。
    • 如果该请求通过且正常,断路器会恢复为关闭状态。

Closed → 触发降级条件 → Open → 熔断时长结束,下一请求 → Half-Open

↑ ↓

└────── 探测失败 ←──── 探测成功 ←──────────────┘

总结

  本篇介绍了Sentinel 实现控制台功能,在服务端的实现原理:通过AOP + 责任链模式实现。并且在调用目标方法时,为每一个请求都创建一份责任链,放入缓存,依次调用。

  后面几个责任链的实现,在规则校验不通过时,都会抛出异常 ,而真正处理的逻辑,在StatisticSlot的catch中,以及SentinelResourceAspect#invokeResourceWithSentinel的entry.exit中,包括处理断路器的状态。

下一篇:Sentinel核心源码分析(下)

相关推荐
xixiaoyunya4 分钟前
Spring Boot 3 统一响应与全局异常处理实战
java·spring boot·后端
余槐i15 分钟前
将AI Agent嵌入现有Java系统时,Spring Boot 3.2的异步冲突与内存泄漏排查
人工智能·spring boot·性能优化·kubernetes·ai agent
JavaGuide20 分钟前
DeepSeek Harness 官方桌面端终于有了!
前端·后端
SFLYQ26 分钟前
隔离内网下 AI Agent 工程实战
后端·agent·ai编程
凤山老林38 分钟前
Spring Boot 集成 Netty 构建高性能 TCP 长连接网关:协议解析、心跳检测与集群广播实战
spring boot·后端·tcp/ip
Json____1 小时前
基于 Spring Boot + Vue3 的在线考试管理系统实战
java·spring boot·后端·it学习·wwwoop.com
2601_962219011 小时前
操作日志全留存架构:万象生鲜系统生鲜业务合规审计底层实现方案
微服务·云原生·架构
Sam_Deep_Thinking1 小时前
如何理解java的信号量
java·后端·面试·程序员
东风破_2 小时前
NestJS 快速入门:先别背装饰器,把一条请求跑明白
后端
❀͜͡傀儡师2 小时前
Spring Boot 实现图片盲水印:基于 DCT 频域算法的隐形数字水印
spring boot·算法