ClusterBuilderSlot,它是 Sentinel 插槽链(Slot Chain)中的一个关键组件,负责:

为每个资源(Resource)创建并关联全局唯一的 ClusterNode,同时支持按调用方(origin)细分统计。

理解它,需要结合 Sentinel 的整体架构,尤其是 “资源统计的三层模型”

  1. DefaultNode:特定上下文(Context)中某个资源的统计节点(局部视图)
  2. ClusterNode:该资源在所有上下文中的全局汇总统计(全局视图)
  3. Origin NodeClusterNode 内部按 origin(调用方)细分的统计(来源视图)

🧩 一、核心职责解析

1. 确保每个资源有且仅有一个 ClusterNode(全局单例)

private static volatile Map<ResourceWrapper, ClusterNode> clusterNodeMap = new HashMap<>();
  • KeyResourceWrapper(包含资源名 + 资源类型,如 EntryType.IN/OUT
  • Value:该资源对应的 ClusterNode

💡 为什么需要全局唯一?
无论你在哪个 Context 中调用 /api/order,Sentinel 都要能统计它的总 QPS、总 RT,用于全局流控、系统保护等。

线程安全设计:写时复制(Copy-on-Write)
synchronized (lock) {
    if (clusterNode == null) {
        clusterNode = new ClusterNode(...);
        HashMap<ResourceWrapper, ClusterNode> newMap = new HashMap<>(...);
        newMap.putAll(clusterNodeMap);
        newMap.put(node.getId(), clusterNode);
        clusterNodeMap = newMap; // 原子引用替换
    }
}
  • 不用 ConcurrentHashMap:因为资源数量稳定后几乎不再变化,读多写少
  • 写时复制:避免锁竞争,读操作无锁(直接读 volatile 引用)

✅ 这是高性能中间件的经典优化:为稳定状态优化读性能


2. DefaultNodeClusterNode 关联

node.setClusterNode(clusterNode);
  • DefaultNode 是当前 Context 中该资源的统计节点(由 NodeSelectorSlot 创建)
  • 通过这行代码,局部节点 → 全局节点 的链接建立完成

🔗 后续统计时:

  • 局部指标(如某个 Context 的 QPS)→ 查 DefaultNode
  • 全局指标(如整个系统的 QPS)→ 查 ClusterNode

3. 支持按 origin 细分统计(来源限流基础)

if (!"".equals(context.getOrigin())) {
    Node originNode = node.getClusterNode().getOrCreateOriginNode(context.getOrigin());
    context.getCurEntry().setOriginNode(originNode);
}
  • 如果当前 Context 设置了 origin(如 "user-app"
  • 就从 ClusterNode 中获取(或创建)该 origin 对应的 StatisticNode
  • 并将其绑定到当前 Entry

效果
当流控规则指定 limitApp="user-app" 时,Sentinel 会检查这个 originNode 的 QPS,而不是全局 ClusterNode


🔄 二、在整个 Slot Chain 中的位置与作用

Sentinel 的插槽链典型顺序:

NodeSelectorSlot → ClusterBuilderSlot → ... → FlowSlot

协作流程

  1. NodeSelectorSlot

    • 创建 DefaultNode(按 Context 隔离)
    • 构建调用树(EntranceNode → DefaultNode
  2. ClusterBuilderSlot

    • 为该资源创建/获取全局 ClusterNode
    • DefaultNode 关联到 ClusterNode
    • 处理 origin 细分
  3. 后续 Slot(如 StatisticSlot, FlowSlot

    • 写入统计数据到 DefaultNodeClusterNode
    • 流控检查时可选择使用 DefaultNode(Context 级)、ClusterNode(全局)或 originNode(来源级)

📊 三、静态方法:提供全局访问入口

public static ClusterNode getClusterNode(String id, EntryType type)
public static ClusterNode getClusterNode(String id)
public static Map<ResourceWrapper, ClusterNode> getClusterNodeMap()
  • 这些方法允许外部(如控制台、监控系统)直接查询任意资源的全局统计
  • 例如:Sentinel Dashboard 展示 /api/order 的 QPS 曲线,就是调用 getClusterNode("/api/order")
public static void resetClusterNodes()
  • 当统计窗口参数(如采样数、时间间隔)动态调整时,重置所有 ClusterNode 的滑动窗口

🌰 四、举个实际例子

假设应用中有两个调用链路:

链路 A(用户下单)

ContextUtil.enter("order-flow", "user-app");
SphU.entry("/api/order"); // Resource: "/api/order", EntryType.IN

链路 B(后台同步)

ContextUtil.enter("sync-job", "admin-service");
SphU.entry("/api/order");

ClusterBuilderSlot 的工作结果:

数据结构 内容
clusterNodeMap { "/api/order" → ClusterNode_A }(全局唯一)
ClusterNode_A - 总 passQps = user-app + admin-service 的总和
- originCountMap = { "user-app" → Node_U, "admin-service" → Node_A }
DefaultNode(order-flow) 关联到 ClusterNode_A,只统计用户下单流量
DefaultNode(sync-job) 关联到 ClusterNode_A,只统计后台同步流量

流控规则可以灵活选择

  • 全局限流:检查 ClusterNode_A.passQps()
  • 来源限流:检查 Node_U.passQps()Node_A.passQps()
  • Context 限流:检查对应 DefaultNode.passQps()

🧠 五、总结:ClusterBuilderSlot 的核心价值

维度 说明
全局聚合 为每个资源建立唯一 ClusterNode,实现跨 Context 的流量汇总
来源隔离 支持按 origin 细分统计,为“针对调用方限流”提供数据基础
高性能设计 写时复制 + 锁优化,适应资源数量稳定的生产环境
架构桥梁 连接局部统计(DefaultNode)与全局统计(ClusterNode),是 Sentinel 多维流控的基石

💡 一句话理解
ClusterBuilderSlot 是 Sentinel 实现“既见树木(Context 局部),又见森林(资源全局),还能识别每棵树的品种(origin)”的关键枢纽。

没有它,Sentinel 就只能做简单的接口限流;有了它,才能实现 精细化、场景化、多租户的流量治理

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐