本文基于Sentinel 1.8.6版本分析

1. SlotChain

我们从入口com.alibaba.csp.sentinel.SphU#entry(java.lang.String) 开始分析。

一路走读下来,会进入到这个方法com.alibaba.csp.sentinel.CtSph#lookProcessChain,查找该资源对应的Slot Chain。

接下来看如何构建这个Slot Chain. Sentinel实现了自己的一套SPI机制,提供了缓存和排序等功能。在@Spi注解上有一个order字段,支持按order从小到大排序。

2. Slot

插槽的接口叫ProcessorSlot,它有4个方法,分别对应入口、出口时自己运行逻辑及调用下一个Slot的入口或出口。

Slot Chain也是插槽的一个实现,作为链条的入口 ,比较特殊的点在于它持有了其他的Slot。

2.1. NodeSelectorSlot

NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;

首先了解一下Node的类继承关系

有三种不同的节点:

Root: 根节点,全局唯一,所有调用的入口,值固定为machine-root,承载在com.alibaba.csp.sentinel.Constants#ROOT字段。它的实现类是EntranceNode.

EntranceNode:DefaultNode的子类,入口节点,一个Context会有一个入口节点,用于统计当前Context的总体流量数据,统计维度为Context。可以调用com.alibaba.csp.sentinel.context.ContextUtil#enter(java.lang.String)设置,若无设置,默认值为sentinel_default_context。它的实现类也是EntranceNode.

DefaultNode:默认节点,用于统计一个resource在当前Context中的流量数据,DefaultNode持有指定的Context和指定的Resource的统计数据,意味着DefaultNode是以Context和Resource为维度的统计节点。它的实现类是DefaultNode.

通过这个调用链路,就可以实现基于调用链路限流。

public class ChainStrategyDemo {

    private static final String RESOURCE_1 = "Resource1";

    private static final Logger logger = LoggerFactory.getLogger(ChainStrategyDemo.class);

    public static void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
// 绑定资源
rule1.setResource(RESOURCE_1);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 可以只对某个链路生效
rule1.setCount(2);
rule1.setStrategy(RuleConstant.STRATEGY_CHAIN);
rule1.setRefResource("context1");
rules.add(rule1); FlowRuleManager.loadRules(rules);
} public static void method(String contextName) {
// 定义资源
try(Entry entry = SphU.entry(RESOURCE_1)){
logger.info("Visit resource 1");
}catch (BlockException e) {
logger.error("{} 被流控了!", contextName);
}
} public static void main(String[] args) throws InterruptedException {
initFlowRules(); ExecutorService executor = Executors.newFixedThreadPool(2); executor.submit(new Task("context1")); executor.submit(new Task("context2")); Thread.sleep(10_000L);
executor.shutdown();
} public static class Task implements Runnable{ private String contextName; public Task(String contextName) {
this.contextName = contextName;
} @Override
public void run() {
ContextUtil.enter(contextName);
for(int i = 0; i <= 4; i++){
method(contextName);
}
}
} }

通过上面的分析,可以得出如下的调用链路。

使用Debug方式,在调用完成后,查看内存中的调用链路

运行结果,只对context1限流

需要注意的是,这里的调用关系并不是代码的调用链路,而是关注调用入口和资源的关系。

再来看下面这个例子,method2嵌套了method1。

	public static void main(String[] args) throws InterruptedException {
initFlowRules(); method1(); method2(); System.out.println("Finished!");
} public static void method1() {
// 定义资源
try(Entry entry = SphU.entry(RESOURCE_1)){
System.out.println("Visit resource 1");
}catch (BlockException e) {
System.out.println("被流控了!");
}
} public static void method2() {
// 定义资源
try(Entry entry = SphU.entry(RESOURCE_2)){
System.out.println("Visit resource 1");
method1();
}catch (BlockException e) {
System.out.println("被流控了!");
}
}

2.2 ClusterBuilderSlot

如果想要以资源的维度来限流,那么必须对调用链路的DefaultNode,以资源的维度做一次汇总,ClusterBuilderSlot正是这个作用。

此插槽用于构建资源ClusterNode 以及调用来源节点。ClusterNode 保持资源运行统计信息(响应时间、QPS、block 数目、线程数、异常数等)以及原始调用者统计信息列表。来源调用者的名字由 ContextUtil.enter(contextName,origin) 中的 origin 标记。

ClusterNode: 资源唯一标识的 ClusterNode 的 runtime 统计。它的实现类是ClusterNode.

Origin: 根据来自不同调用者的统计信息,在ClusterNode中有一个Map,专门按Origin调用来源统计不同的数据,默认是空字符串。在访问资源前,可以通过com.alibaba.csp.sentinel.context.ContextUtil#enter(java.lang.String, java.lang.String)指定调用来源。它的实现类是StatisticNode.

所以,完整的关系图如下,绿色表示这些节点存储了不同维度的统计数据

通过LimitApp,就可以实现基于调用来源的限流。

	public static void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
// 绑定资源
rule1.setResource(RESOURCE_1);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 可以只对某个来源生效
rule1.setCount(2);
// 默认也是这个值
rule1.setStrategy(RuleConstant.STRATEGY_DIRECT);
rule1.setLimitApp(DEFAULT_LIMIT_APP);
rules.add(rule1); FlowRuleManager.loadRules(rules);
} public static void method(String origin) {
// 定义资源
try (Entry entry = SphU.entry(RESOURCE_1)) {
logger.info("Visit resource 1");
} catch (BlockException e) {
logger.error("{} 被流控了!", origin);
}
} public static void main(String[] args) throws InterruptedException {
initFlowRules(); ExecutorService executor = Executors.newFixedThreadPool(2); executor.submit(new Task(DEFAULT_LIMIT_APP)); executor.submit(new Task("AnotherLimitApp")); Thread.sleep(10_000L);
executor.shutdown();
} public static class Task implements Runnable { private String origin; public Task(String origin) {
this.origin = origin;
} @Override
public void run() {
for (int i = 0; i <= 4; i++) {
ContextUtil.enter(DEFAULT_ENTRANCE, origin);
method(origin);
}
}
}

通过上面的介绍,我们知道了有不同的Node,并且流量控制有不同的策略Strategy,还有可以通过调用来源来限制,那么不同的情况下会使用什么节点进行限流判断呢?

在进行限流判断前,会调用这个方法选择合适的节点 com.alibaba.csp.sentinel.slots.block.flow.FlowRuleChecker#selectNodeByRequesterAndStrategy

调用来源/策略 Direct Relate Chain
指定来源 origin cluster current(当前节点就是链路第三层的DefaultNode)
不指定来源 cluster cluster current(当前节点就是链路第三层的DefaultNode)
指定来源之外(Other,其实也是指定来源) origin cluster current(当前节点就是链路第三层的DefaultNode)

可以看到,如果选择了Chain基于链路限流,则肯定是使用当前节点,无法指定来源;如果选择了Relate基于关联关系,则肯定是使用cluster; 如果选择了Direct,就要看有没有指定来源,若指定了则使用origin,否则还是使用cluster.

Sentinel系列之SlotChain、NodeSelectorSlot、ClusterBuilderSlot分析的更多相关文章

  1. SequoiaDB 系列之七 :源码分析之catalog节点

    这一篇紧接着上一篇SequoiaDB 系列之六 :源码分析之coord节点来讲 在上一篇中,分析了coord转发数据包到catalog节点(也有可能是data节点,视情况而定).这一次,我们继续分析上 ...

  2. SequoiaDB 系列之六 :源码分析之coord节点

    好久不见. 在上一篇SequoiaDB 系列之五   :源码分析之main函数,有讲述进程开始运行时,会根据自身的角色,来初始化不同的CB(控制块,control block). 在之前的一篇Sequ ...

  3. java基础解析系列(九)---String不可变性分析

    java基础解析系列(九)---String不可变性分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---In ...

  4. java多线程系列(九)---ArrayBlockingQueue源码分析

    java多线程系列(九)---ArrayBlockingQueue源码分析 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 j ...

  5. 智能合约语言 Solidity 教程系列4 - 数据存储位置分析

    写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么 这部分的内容官方英文文档讲的不是很透,因此我在参考Soli ...

  6. Java集合系列[4]----LinkedHashMap源码分析

    这篇文章我们开始分析LinkedHashMap的源码,LinkedHashMap继承了HashMap,也就是说LinkedHashMap是在HashMap的基础上扩展而来的,因此在看LinkedHas ...

  7. Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式

    在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...

  8. Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式

    通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...

  9. Java并发系列[5]----ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...

  10. [大数据从入门到放弃系列教程]第一个spark分析程序

    [大数据从入门到放弃系列教程]第一个spark分析程序 原文链接:http://www.cnblogs.com/blog5277/p/8580007.html 原文作者:博客园--曲高终和寡 **** ...

随机推荐

  1. Loguru:优雅的日志管理模块

    安装 pip3 install loguru 日志等级 等级 方法 TRACE logger.trace() DEBUG logger.debug() INFO logger.info() SUCES ...

  2. 逆向之Ja3指纹学习

    声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! tls tls实际上前身就 ...

  3. 【C++ Primer】2.1 基本内置类型

    1. 基本内置类型 基本算数类型: 类型 含义 最小尺寸 bool 布尔类型 8bits char 字符 8bits wchar_t 宽字符 16bits char16_t Unicode字符 16b ...

  4. [ARM 汇编]高级部分—性能优化与调试—3.4.1 性能分析与优化策略

    性能优化是嵌入式系统开发中的一个重要环节,尤其是在资源受限的环境下.性能优化的目标是提高代码执行速度.降低功耗和减少内存占用.在本章节中,我们将讨论性能分析与优化策略,并通过实例来学习如何应用这些策略 ...

  5. MODBUS-TCP转Ethernet IP 网关连接空压机配置案例

    本案例是工业现场应用捷米特JM-EIP-TCP的Ethernet/IP转Modbus-TCP网关连接欧姆龙PLC与空压机的配置案例.使用设备:欧姆龙PLC,捷米特JM-EIP-TCP网关, ETHER ...

  6. C#.NET Framework 使用BC库(BouncyCastle) RSA 公钥加密 私钥解密 ver:20230706

    C#.NET Framework 使用BC库(BouncyCastle) RSA 公钥加密 私钥解密 ver:20230706 环境说明: .NET Framework 4.6 的控制台程序 . 20 ...

  7. ASP.NET MVC4 学习笔记-4

    添加验证--Adding Validation 现在我们要为程序增加数据验证.如果不增加数据验证的话,我们的用户可能会输入错误的数据或者提交一个空白的表格. 在MVC应用程序中,数据验证通常要在域模型 ...

  8. 关于DVWA靶场高难度命令执行的代码审计

    需要的环境:dvwa 使用的工具:PHP手册 high难度源代码: <?php if( isset( $_POST[ 'Submit' ] ) ) { // Get input $target ...

  9. 关于 yield 关键字(C#)

    〇.前言 yield 关键字的用途是把指令推迟到程序实际需要的时候再执行,这个特性允许我们更细致地控制集合每个元素产生的时机. 对于一些大型集合,加载起来比较耗时,此时最好是先返回一个来让系统持续展示 ...

  10. 长连接:chatgpt流式响应背后的逻辑

    一.前言: 提起长连接,我们并不陌生,最常见的长连接非websocket莫属了.即使没有在项目中实际用过,至少也应该有所接触.长连接指在一次网络通信中,客户端与服务器之间建立一条持久的连接,可以在多次 ...