Sentinel限流核心逻辑解析

java 复制代码
    static Node selectNodeByRequesterAndStrategy(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node) {
        // The limit app should not be empty.
        String limitApp = rule.getLimitApp();
        int strategy = rule.getStrategy();
        String origin = context.getOrigin();

        if (limitApp.equals(origin) && filterOrigin(origin)) {
            if (strategy == RuleConstant.STRATEGY_DIRECT) {
                // Matches limit origin, return origin statistic node.
                return context.getOriginNode();
            }

            return selectReferenceNode(rule, context, node);
        } else if (RuleConstant.LIMIT_APP_DEFAULT.equals(limitApp)) {
            if (strategy == RuleConstant.STRATEGY_DIRECT) {
                // Return the cluster node.
                return node.getClusterNode();
            }

            return selectReferenceNode(rule, context, node);
        } else if (RuleConstant.LIMIT_APP_OTHER.equals(limitApp)
            && FlowRuleManager.isOtherOrigin(origin, rule.getResource())) {
            if (strategy == RuleConstant.STRATEGY_DIRECT) {
                return context.getOriginNode();
            }

            return selectReferenceNode(rule, context, node);
        }

        return null;
    }

这段 selectNodeByRequesterAndStrategy 方法是 Sentinel 流控规则中决定"对哪个统计节点进行限流判断" 的核心逻辑。它结合了 限流目标(limitApp)限流策略(strategy)当前请求上下文(Context) ,动态选择一个 Node 对象用于后续的流量控制判断。


🧠 一、方法作用

返回一个 Node 对象,代表"要被限流检查的统计对象"。

  • 如果返回 null → 表示 不触发限流(直接放行)。
  • 如果返回非 null → 后续用该 Node 的 QPS/线程数等指标与阈值比较。

🔑 二、关键变量说明

变量 含义
limitApp = rule.getLimitApp() 限流规则的目标调用方: • 具体应用名(如 "appA") • default:所有来源统一限流 • other:除白名单外的所有来源
origin = context.getOrigin() 当前请求的实际调用方(由上游传递,如通过 header 设置)
strategy = rule.getStrategy() 限流策略: • STRATEGY_DIRECT (0):直接限流 • STRATEGY_RELATE (1):关联资源限流 • STRATEGY_CHAIN (2):链路限流
node 当前资源的 DefaultNode(记录该资源的总体指标)
context.getOriginNode() 记录 该 origin 对当前资源的访问指标(如 appA 调用 /order 的 QPS)
node.getClusterNode() 当前资源的全局 ClusterNode(所有 origin 汇总)

📐 三、逻辑分支详解 + 场景举例

✅ 分支 1:limitApp == origin 且 origin 有效(非 default/other)

java 复制代码
if (limitApp.equals(origin) && filterOrigin(origin)) {
    if (strategy == STRATEGY_DIRECT) {
        return context.getOriginNode(); // 👈 针对特定 origin 的统计
    }
    return selectReferenceNode(rule, context, node); // 关联/链路模式
}
✅ 场景 1.1:精准限流某个调用方(DIRECT)
  • 规则:resource="pay", limitApp="mobile", strategy=DIRECT
  • 请求:origin="mobile"
  • 结果:返回 context.getOriginNode() → 检查 mobile 调用 pay 的 QPS
  • 💡 效果:只限制 mobile 应用,web 应用不受影响。
✅ 场景 1.2:关联限流(RELATE)
  • 规则:resource="pay", limitApp="mobile", strategy=RELATE, refResource="order"
  • 请求:origin="mobile"
  • 结果:调用 selectReferenceNode(...) → 返回 ClusterBuilderSlot.getClusterNode("order")
  • 💡 效果:当 order 接口的总 QPS 超过阈值,就限制 mobile 调用 pay。

注意:此时限流依据是 refResource(order)的全局流量,不是 pay 本身的流量。


✅ 分支 2:limitApp == "default"

java 复制代码
else if (RuleConstant.LIMIT_APP_DEFAULT.equals(limitApp)) {
    if (strategy == STRATEGY_DIRECT) {
        return node.getClusterNode(); // 👈 全局统计
    }
    return selectReferenceNode(rule, context, node);
}
✅ 场景 2.1:对所有调用方统一限流(DIRECT)
  • 规则:resource="pay", limitApp="default", strategy=DIRECT
  • 请求:origin="web""mobile"""
  • 结果:返回 node.getClusterNode() → 检查 pay 接口的总 QPS
  • 💡 效果:无论谁调用,只要 pay 总 QPS > 阈值,就限流。
✅ 场景 2.2:default + RELATE
  • 规则:resource="pay", limitApp="default", strategy=RELATE, refResource="user"
  • 结果:返回 ClusterNode("user")
  • 💡 效果:当 user 接口总流量过高时,限制所有调用方访问 pay。

✅ 分支 3:limitApp == "other" 且 origin 属于 "other"

java 复制代码
else if (RuleConstant.LIMIT_APP_OTHER.equals(limitApp)
    && FlowRuleManager.isOtherOrigin(origin, rule.getResource())) {
    if (strategy == STRATEGY_DIRECT) {
        return context.getOriginNode();
    }
    return selectReferenceNode(rule, context, node);
}

isOtherOrigin(origin, resource) 通常指:

  • origin 不在该 resource 的白名单中(即"非信任来源")
✅ 场景 3.1:限制"非白名单"调用方
  • 假设系统配置:resource="admin-api" 的白名单为 ["internal"]
  • 规则:limitApp="other", strategy=DIRECT
  • 请求 A:origin="internal" → ❌ 不进入此分支 → 返回 null → 不限流
  • 请求 B:origin="hacker" → ✅ 进入此分支 → 返回 originNode("hacker")
  • 💡 效果:只限制非白名单调用者,内部系统畅通。

❌ 默认情况:返回 null

如果以上都不匹配(例如 limitApp="appA"origin="appB"),则:

java 复制代码
return null;

不触发限流,请求直接通过。

✅ 场景 4:规则不匹配当前请求
  • 规则:limitApp="mobile"
  • 请求:origin="web"
  • 结果:跳过该规则 → 继续检查下一条规则(或最终放行)

💡 这是 Sentinel 规则"按需生效"的体现:规则只对目标 origin 生效。


🧩 四、辅助方法 selectReferenceNode 补充说明

java 复制代码
static Node selectReferenceNode(FlowRule rule, Context context, DefaultNode node) {
    String refResource = rule.getRefResource();
    int strategy = rule.getStrategy();

    if (StringUtil.isEmpty(refResource)) return null;

    if (strategy == STRATEGY_RELATE) {
        return ClusterBuilderSlot.getClusterNode(refResource); // 全局关联资源节点
    }

    if (strategy == STRATEGY_CHAIN) {
        if (!refResource.equals(context.getName())) return null; // 必须是入口资源
        return node; // 当前节点(但仅在指定链路上)
    }
    return null;
}

场景补充:

  • STRATEGY_CHAIN :只有当当前调用链的 入口资源(context.getName())等于 refResource 时才限流。
    • 例:refResource = "gateway-entry",只有从网关入口进来的链路才受限制,内部服务间调用不受限。

✅ 五、总结:决策流程图

是 是 否 否 是 是 否 否 是 是 否 否 开始 limitApp == origin? strategy == DIRECT? 返回 originNode 调用 selectReferenceNode limitApp == 'default'? strategy == DIRECT? 返回 clusterNode limitApp == 'other' 且 origin 属于 other? strategy == DIRECT? 返回 originNode 返回 null → 不限流


💡 六、最佳实践建议

  1. DIRECT + specific origin:用于多租户隔离、防刷。
  2. DEFAULT + DIRECT:用于保护核心接口整体容量。
  3. RELATE:用于保护下游依赖(如 DB、第三方 API)。
  4. CHAIN:用于防止入口流量打垮内部服务。
  5. OTHER:用于安全防护(黑名单式限流)。

理解 selectNodeByRequesterAndStrategy 是掌握 Sentinel 精细化流控的关键!

相关推荐
小王师傅662 小时前
【轻松入门SpringBoot】从0到1搭建web 工程(下)-在实践中对比SpringBoot和Spring框架
java·spring boot·spring
趁你还年轻_2 小时前
spring Ai Alibaba 和 langChain4j的区别
java·人工智能·spring
小白勇闯网安圈2 小时前
wife_wife、题目名称-文件包含、FlatScience
javascript·python·网络安全·web·原型模式
Q_Q5110082852 小时前
python+django/flask+vue的B站数据分析可视化系统
spring boot·python·django·flask·node.js·php
运维@小兵2 小时前
使用Spring-AI的chatMemoryAdvisor实现多轮会话
java·人工智能·spring
黑客思维者2 小时前
Python自动化办公全攻略:Excel/Word/PDF/邮件批量处理
python·自动化·excel
苏小瀚2 小时前
[JavaEE] SpringBoot快速入门
java·spring boot·intellij-idea
chikaaa2 小时前
java高并发高可用场景解决方案
java·开发语言
小学鸡!2 小时前
部署jar包时指定配置文件
java·python·jar