sentinel 基本原理
1.整体设计
sentinel的整体设计比较简单.sentinel把提供的每个功能都封装成一个slot,然后通过一个slotchain(责任链模式)把所有的功能串联起来,从而将不同的功能组合起来.sentinel的功能又分为统计功能和面向用户的限流,熔断降级等功能.sentinel的统计功能是面向用户功能的基础,sentinel通过统计信息和用户配置的rule来实现用户功能.所有的统计信息都被封装到一个一个的StatisticNode中.而用户配置的信息保存在格式的Rule中(FlowRule,DegradRule等).sentinel的整体框架如下.
2.核心类
2.1 Entry
每一次资源调用都会创建一个 Entry
。Entry
包含了资源名、curNode(当前统计节点)、originNode(来源统计节点)等信息。
CtEntry
为普通的 Entry
,在调用 SphU.entry(xxx)
的时候创建。特性:Linked entry within current context(内部维护着 parent
和 child
)
需要注意的一点:CtEntry 构造函数中会做调用链的变换,即将当前 Entry 接到传入 Context 的调用链路上(setUpEntryFor
)。
资源调用结束时需要 entry.exit()
。exit 操作会过一遍 slot chain exit,恢复调用栈,exit context 然后清空 entry 中的 context 防止重复调用。
2.2 Context
Context 代表调用链路上下文,贯穿一次调用链路中的所有 Entry
。Context 维持着入口节点(entranceNode
)、本次调用链路的 curNode、调用来源(origin
)等信息。Context 名称即为调用链路入口名称。
Context可以在资源调用之前手动通过ContextUtil.enter(name,origin)创建,name为当前context的名称,origin为调用方名称,当配置了调用方限流的时候会用到.在创建Context的时候会校验打当前Context对应的name的EntranceNode是否被创建,如果没有创建则会先创建EnranceNode.所有同名的Context会共享一个EnranceNode,这个是为了调用链路限流的时候使用.如果不手动创建Context则在调用了SphU.entry()方法之后会自动调用ContextUtil创建一个Context,和手动创建效果一样.
Context 维持的方式:通过 ThreadLocal 传递,只有在入口 enter
的时候生效。由于 Context 是通过 ThreadLocal 传递的,因此对于异步调用链路,线程切换的时候会丢掉 Context,因此需要手动通过 ContextUtil.runOnContext(context, f)
来变换 context。
2.3 Node
Sentinel 里面的各种种类的统计节点:
-
StatisticNode
:最为基础的统计节点,包含秒级和分钟级两个滑动窗口结构。具体sentinel滑动窗口的实现后面再讲.DefaultNode
:链路节点,用于统计调用链路上某个资源的数据,维持树状结构。继承自StatisticNode,并且同一个资源的DefaultNode共同持有一个统统的ClusterNode,这个是为了方便统计该资源全局的统计信息.DefaultNode创建的维度是resource*context,并且所有的DefaultNode都保存在NodeSelectSlot的map中,同一个resouce和context的时候会从map中获取,该节点的统计信息主要使用在根据调用链路限流的时候.ClusterNode
:簇点,用于统计每个资源全局的数据(不区分调用链路),继承自StatisticNode.ClusterNode也存放该资源的按来源区分的调用数据,并且把数据保存在Map<String,StatisticNode> originCountMap中.特别的,Constants.ENTRY_NODE节点中用于统计全局的入口资源数据.创建维度为resource.数据来源节点的创建维度为 resouce*originEntranceNode
:入口节点,特殊的链路节点,对应某个 Context 入口的所有调用数据,创建维度为resource。Constants.ROOT
节点也是入口节点。
2.4 Slot
Slot中主要定义sentinel的功能,sentinel中默认提供了以下Slot
-
- NodeSelectorSlot:主要用来创建DefaultNode节点,为后面的统计信息做准备.
- ClusterBuilderSlot:主要用来创建每个资源的ClusterNode,并且把ClusterNode保存在ClusterBuilderSlot的静态属性ClusterNodeMap中.
- LogSlot:主要作用为当sentinel通过各种规则拒绝了当前请求之后记录资源名称和限流信息.
- StatisticSlot:记录当前资源的统计信息,包括QPS,线程数,通过请求数量,拒绝请求数量等所有的统计信息.
- AuthoritySlot:根据配置的黑白名单规则校验当前请求是否符合规则,否则抛出AuthorityException.详细过程后面再讲.
- SystemSlot:根据系统当前负载,调用SystemRuleManager根据用户配置的系统负载规则校验当前请求是否可以通过,如果不能通过则抛出SystemBlockException
- FlowSlot:通过调用FlowRuleChecker和用户配置的限流规则校验当前请求是否符合规则,如果不符合则抛出FlowException,具体过程后面讲.
- DegradeSlot:根据用户配置的熔断规则判断当前资源是否需要熔断,如果需要则抛出DegradeException
2.5 ProcessSlotChain
Sentinel 的核心骨架,将不同的 Slot 按照顺序串在一起(责任链模式),从而将不同的功能(限流、降级、系统保护)组合在一起.processSlotChain也实现了AbstractLinkedProcessorSlot,在默认的DefaultProcessSlotChain中定义了first和end两个AbstractLinkedProcessSlot,当调用ProcessSlotChain的entry方法的时候ProcessSlotChain会调用fireEntry方法,而fireEntry方法会调用first的entry方法.由于每个AbstractLinkedProcessorSlot的entry方法中都会调用fireEntry]方法,而每个fireEntry又都会调用next.entry方法,所以整个slotChain都会执行一遍.