Sentinel 流控原理深度解析:从SlotChain到热点参数限流的设计哲学

文章目录

  • [Sentinel 流控原理深度解析:从SlotChain到热点参数限流的设计哲学](#Sentinel 流控原理深度解析:从SlotChain到热点参数限流的设计哲学)
    • [📊 目录](#📊 目录)
    • [🎯 一、Sentinel设计哲学:从被动防御到主动治理](#🎯 一、Sentinel设计哲学:从被动防御到主动治理)
      • [💡 Sentinel的核心设计思想](#💡 Sentinel的核心设计思想)
    • [🔗 二、SlotChain:可插拔的责任链架构](#🔗 二、SlotChain:可插拔的责任链架构)
      • [💡 SlotChain的设计哲学](#💡 SlotChain的设计哲学)
      • [🔧 SlotChain实现深度解析](#🔧 SlotChain实现深度解析)
    • [⚖️ 三、QPS vs 并发数:两种限流模式深度对比](#⚖️ 三、QPS vs 并发数:两种限流模式深度对比)
      • [💡 两种限流模式的本质差异](#💡 两种限流模式的本质差异)
    • [🔥 四、热点参数限流:精准控制的智慧](#🔥 四、热点参数限流:精准控制的智慧)
      • [💡 热点参数限流的设计思想](#💡 热点参数限流的设计思想)
      • [🔧 热点参数限流实现深度解析](#🔧 热点参数限流实现深度解析)

Sentinel 流控原理深度解析:从SlotChain到热点参数限流的设计哲学

📊 目录

  • 🎯 一、Sentinel设计哲学:从被动防御到主动治理
  • 🔗 二、SlotChain:可插拔的责任链架构
  • ⚖️ 三、QPS vs 并发数:两种限流模式深度对比
  • 🔥 四、热点参数限流:精准控制的智慧
  • 📈 五、滑动窗口算法:时间窗口的魔法
  • 🎪 六、集群流控:分布式一致性挑战
  • 🔧 七、生产实践:配置、监控与调优

🎯 一、Sentinel设计哲学:从被动防御到主动治理

💡 Sentinel的核心设计思想

Sentinel与传统限流框架的本质区别

java 复制代码
/**
 * Sentinel设计哲学解析
 * 从防御到治理的演进
 */
@Component
@Slf4j
public class SentinelPhilosophy {
    
    /**
     * 流量治理的四个维度
     */
    public enum TrafficGovernanceDimension {
        /**
         * 维度一:流量控制
         * 哲学:预防胜于治疗
         */
        FLOW_CONTROL(
            "流量控制",
            "预防系统过载,保护系统稳定性",
            """
            设计思想:
            - 在入口处控制流量
            - 避免突发流量击垮系统
            - 平滑流量,削峰填谷
            """,
            """
            实现方式:
            - QPS限流
            - 并发数限流
            - 匀速排队
            - 冷启动
            """
        ),
        
        /**
         * 维度二:熔断降级
         * 哲学:快速失败,避免雪崩
         */
        CIRCUIT_BREAKER(
            "熔断降级",
            "保护系统免受过载和故障影响",
            """
            设计思想:
            - 监控依赖服务的健康状态
            - 异常时快速失败
            - 避免资源耗尽导致雪崩
            """,
            """
            实现方式:
            - 慢调用比例熔断
            - 异常比例熔断
            - 异常数熔断
            - 自适应恢复
            """
        ),
        
        /**
         * 维度三:系统保护
         * 哲学:自我保护,确保存活
         */
        SYSTEM_PROTECT(
            "系统保护", 
            "保护系统自身,防止被拖垮",
            """
            设计思想:
            - 监控系统自身指标
            - 根据系统负载动态限流
            - 保证系统不崩溃
            """,
            """
            实现方式:
            - LOAD自适应保护
            - CPU使用率保护
            - 平均RT保护
            - 线程数保护
            """
        ),
        
        /**
         * 维度四:热点参数
         * 哲学:精准控制,资源优化
         */
        HOT_PARAM(
            "热点参数",
            "对热点资源进行精准控制",
            """
            设计思想:
            - 识别热点参数
            - 针对性限流
            - 优化资源分配
            """,
            """
            实现方式:
            - 参数统计
            - 热点识别
            - 差异化限流
            """
        );
        
        private final String name;
        private final String purpose;
        private final String philosophy;
        private final String implementation;
    }
    
    /**
     * Sentinel与传统限流的对比
     */
    @Data
    @Builder
    public static class Comparison {
        // 传统限流的问题
        public static class TraditionalLimiterProblems {
            /**
             * 1. 静态配置
             */
            public static final String STATIC_CONFIG = """
                // 传统限流:硬编码配置
                public class TraditionalRateLimiter {
                    private static final int QPS_LIMIT = 100; // 硬编码
                    
                    public boolean tryAcquire() {
                        // 固定限流值
                        return counter < QPS_LIMIT;
                    }
                }
                
                问题:
                - 无法动态调整
                - 难以适应变化流量
                - 每个服务需要单独配置
                """;
            
            /**
             * 2. 缺乏维度
             */
            public static final String LACK_DIMENSIONS = """
                // 传统限流:单一维度
                public boolean allowRequest() {
                    // 只有QPS一个维度
                    return getCurrentQps() < MAX_QPS;
                }
                
                问题:
                - 无法区分调用来源
                - 无法识别热点数据
                - 无法进行精准控制
                """;
            
            /**
             * 3. 被动防御
             */
            public static final String PASSIVE_DEFENSE = """
                // 传统限流:被动响应
                public Response handleRequest(Request req) {
                    if (!rateLimiter.tryAcquire()) {
                        return Response.error("Rate limited"); // 被动拒绝
                    }
                    return process(req);
                }
                
                问题:
                - 只有拒绝,没有治理
                - 无法自适应调整
                - 无法学习流量模式
                """;
        }
        
        // Sentinel的解决方案
        public static class SentinelSolutions {
            /**
             * 1. 动态规则
             */
            public static final String DYNAMIC_RULES = """
                // Sentinel:动态规则配置
                @Configuration
                public class SentinelConfig {
                    
                    @PostConstruct
                    public void initRules() {
                        // 从配置中心加载规则
                        List<FlowRule> rules = loadRulesFromNacos();
                        
                        // 动态更新规则
                        FlowRuleManager.loadRules(rules);
                        
                        // 监听规则变化
                        registerRuleChangeListener();
                    }
                    
                    // 运行时调整规则
                    public void adjustRule(String resource, int newQps) {
                        List<FlowRule> rules = FlowRuleManager.getRules();
                        rules.stream()
                            .filter(r -> r.getResource().equals(resource))
                            .forEach(r -> r.setCount(newQps));
                        FlowRuleManager.loadRules(rules);
                    }
                }
                
                优势:
                - 规则动态生效
                - 无需重启服务
                - 支持灰度发布
                """;
            
            /**
             * 2. 多维度控制
             */
            public static final String MULTI_DIMENSION = """
                // Sentinel:多维度流量控制
                public class MultiDimensionControl {
                    
                    // 1. 调用方维度
                    @SentinelResource(
                        value = "getUserInfo",
                        blockHandler = "userBlockHandler",
                        blockHandlerClass = UserBlockHandler.class
                    )
                    public User getUser(String userId, String source) {
                        // 根据调用方(source)进行不同限流
                        return userService.getUser(userId);
                    }
                    
                    // 2. 热点参数维度
                    @SentinelResource(
                        value = "queryProduct",
                        blockHandler = "hotParamBlockHandler"
                    )
                    public Product queryProduct(
                        @RequestParam Long productId,
                        @RequestParam String userId) {
                        // 对productId进行热点限流
                        return productService.getProduct(productId);
                    }
                    
                    // 3. 系统维度
                    @PostConstruct  
                    public void initSystemRule() {
                        SystemRule rule = new SystemRule();
                        rule.setHighestSystemLoad(4.0);  // 系统Load保护
                        rule.setAvgRt(100);              // 平均RT保护
                        rule.setMaxThread(500);          // 线程数保护
                        rule.setQps(1000);               // 入口QPS保护
                        SystemRuleManager.loadRules(Collections.singletonList(rule));
                    }
                }
                
                优势:
                - 精细化控制
                - 资源优化分配
                - 防止热点问题
                """;
            
            /**
             * 3. 主动治理
             */
            public static final String ACTIVE_GOVERNANCE = """
                // Sentinel:主动流量治理
                @Component
                public class ActiveTrafficGovernance {
                    
                    // 1. 实时监控
                    @Scheduled(fixedDelay = 5000)
                    public void monitorAndAdjust() {
                        // 获取实时指标
                        ClusterNode node = ClusterBuilderSlot.getClusterNode("resource");
                        long passQps = node.passQps();
                        long blockQps = node.blockQps();
                        double blockRatio = (double) blockQps / (passQps + blockQps);
                        
                        // 根据指标自动调整
                        if (blockRatio > 0.1) { // 阻塞率过高
                            adjustRule("resource", RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
                        } else if (blockRatio < 0.01) { // 阻塞率过低
                            adjustRule("resource", RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
                        }
                    }
                    
                    // 2. 自适应保护
                    public void adaptiveProtection() {
                        // 根据系统负载动态调整
                        double systemLoad = getSystemLoad();
                        if (systemLoad > 0.8) {
                            // 负载过高,启用激进限流
                            enableAggressiveLimiting();
                        } else {
                            // 负载正常,恢复正常
                            enableNormalLimiting();
                        }
                    }
                    
                    // 3. 流量整形
                    public void trafficShaping() {
                        // 匀速排队模式
                        FlowRule rule = new FlowRule("resource");
                        rule.setCount(100);
                        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
                        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
                        rule.setMaxQueueingTimeMs(500); // 排队时间
                        FlowRuleManager.loadRules(Collections.singletonList(rule));
                    }
                }
                
                优势:
                - 主动调整,而非被动响应
                - 自适应流量变化
                - 智能化流量治理
                """;
        }
    }
}

🔗 二、SlotChain:可插拔的责任链架构

💡 SlotChain的设计哲学

责任链模式在流量控制中的应用
Slot执行链核心流程
默认
入口
自定义
通过
拒绝








请求进入
SlotChain处理器

  1. NodeSelectorSlot 选择资源节点
    默认节点
    入口节点
    自定义节点
  2. ClusterBuilderSlot 构建ClusterNode
    统计集群指标
  3. LogSlot 记录请求日志
  4. StatisticSlot 统计决策
    更新通过统计
    更新拒绝统计
  5. SystemSlot 记录拒绝原因
    返回拒绝结果
    系统保护检查
    系统是否过载?
    系统保护生效
  6. AuthoritySlot 授权检查
    是否有权限?
    权限不足
  7. FlowSlot 流量控制检查
    是否限流?
    流量控制生效
  8. DegradeSlot 熔断降级检查
    是否熔断?
    熔断生效
  9. 执行业务逻辑 实际业务调用
  10. 返回结果

🔧 SlotChain实现深度解析

java 复制代码
/**
 * SlotChain实现深度解析
 * 展示Sentinel责任链的核心实现
 */
@Slf4j
public class SlotChainDeepDive {
    
    /**
     * SlotChain构建器
     */
    public static class DefaultProcessorSlotChain extends ProcessorSlotChain {
        
        // Slot链头节点
        private AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {
            @Override
            public void entry(Context context, ResourceWrapper resourceWrapper, 
                            Object param, int count, boolean prioritized, Object... args) throws Throwable {
                // 链头,调用下一个Slot
                super.fireEntry(context, resourceWrapper, param, count, prioritized, args);
            }
            
            @Override
            public void exit(Context context, ResourceWrapper resourceWrapper, 
                           int count, Object... args) {
                super.fireExit(context, resourceWrapper, count, args);
            }
        };
        
        // 当前Slot指针
        private AbstractLinkedProcessorSlot<?> end = first;
        
        /**
         * 添加Slot到链尾
         */
        @Override
        public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
            end.setNext(protocolProcessor);
            end = protocolProcessor;
        }
        
        /**
         * 执行entry方法(请求进入)
         */
        @Override
        public void entry(Context context, ResourceWrapper resourceWrapper, 
                        Object param, int count, boolean prioritized, Object... args) throws Throwable {
            first.transformEntry(context, resourceWrapper, param, count, prioritized, args);
        }
        
        /**
         * 执行exit方法(请求退出)
         */
        @Override
        public void exit(Context context, ResourceWrapper resourceWrapper, 
                       int count, Object... args) {
            first.exit(context, resourceWrapper, count, args);
        }
    }
    
    /**
     * NodeSelectorSlot:节点选择器
     * 负责创建调用链路节点
     */
    public static class NodeSelectorSlot extends AbstractLinkedProcessorSlot<Object> {
        
        @Override
        public void entry(Context context, ResourceWrapper resourceWrapper, 
                        Object param, int count, boolean prioritized, Object... args) throws Throwable {
            
            // 1. 获取或创建DefaultNode
            DefaultNode node = context.getCurNode();
            if (node == null) {
                // 创建当前资源的节点
                node = new DefaultNode(resourceWrapper, null);
                context.setCurNode(node);
            }
            
            // 2. 构建调用链
            if (context.getCurEntry().getCurNode() == null) {
                context.getCurEntry().setCurNode(node);
            }
            
            // 3. 构建调用关系
            DefaultNode selectedNode = null;
            if (context.getOrigin() != null) {
                // 按调用方构建节点树
                String origin = context.getOrigin();
                selectedNode = context.getOrCreateOriginNode(origin);
                selectedNode.addChild(node);
            }
            
            // 4. 调用下一个Slot
            fireEntry(context, resourceWrapper, param, count, prioritized, args);
        }
        
        @Override
        public void exit(Context context, ResourceWrapper resourceWrapper, 
                       int count, Object... args) {
            // 清理上下文
            if (context.getCurEntry() != null) {
                context.getCurEntry().setCurNode(null);
            }
            fireExit(context, resourceWrapper, count, args);
        }
    }
    
    /**
     * StatisticSlot:统计Slot
     * 核心的统计逻辑实现
     */
    public static class StatisticSlot extends AbstractLinkedProcessorSlot<Object> {
        
        @Override
        public void entry(Context context, ResourceWrapper resourceWrapper, 
                        Object param, int count, boolean prioritized, Object... args) throws Throwable {
            
            try {
                // 1. 执行后续Slot
                fireEntry(context, resourceWrapper, param, count, prioritized, args);
                
                // 2. 请求通过,更新统计
                for (ProcessorSlotEntryCallback<Object> handler : StatisticSlotCallbackRegistry.getEntryCallbacks()) {
                    handler.onPass(context, resourceWrapper, param, count, args);
                }
                
                // 3. 更新通过计数
                recordPass(resourceWrapper, count, args);
                
            } catch (BlockException e) {
                // 4. 请求被限流/降级
                for (ProcessorSlotEntryCallback<Object> handler : StatisticSlotCallbackRegistry.getEntryCallbacks()) {
                    handler.onBlocked(e, context, resourceWrapper, param, count, args);
                }
                
                // 5. 更新阻塞计数
                recordBlock(resourceWrapper, count, args, e);
                
                throw e;
                
            } catch (Throwable e) {
                // 6. 业务异常
                for (ProcessorSlotEntryCallback<Object> handler : StatisticSlotCallbackRegistry.getEntryCallbacks()) {
                    handler.onError(context, resourceWrapper, e, param, count, args);
                }
                
                // 7. 更新异常计数
                recordError(resourceWrapper, count, args, e);
                
                throw e;
            }
        }
        
        @Override
        public void exit(Context context, ResourceWrapper resourceWrapper, 
                       int count, Object... args) {
            
            // 1. 获取响应时间
            long rt = TimeUtil.currentTimeMillis() - context.getCurEntry().getCreateTime();
            
            // 2. 更新完成计数
            recordComplete(resourceWrapper, count, args, rt);
            
            // 3. 调用完成回调
            for (ProcessorSlotExitCallback handler : StatisticSlotCallbackRegistry.getExitCallbacks()) {
                handler.onExit(context, resourceWrapper, count, args);
            }
            
            // 4. 执行后续Slot的exit
            fireExit(context, resourceWrapper, count, args);
        }
        
        /**
         * 记录通过计数
         */
        private void recordPass(ResourceWrapper resourceWrapper, int count, Object... args) {
            // 更新各个维度的统计
            ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(resourceWrapper.getName());
            if (clusterNode != null) {
                clusterNode.addPassRequest(count);
            }
            
            DefaultNode defaultNode = (DefaultNode) CtSph.getContext().getCurNode();
            if (defaultNode != null) {
                defaultNode.addPassRequest(count);
            }
            
            String origin = CtSph.getContext().getOrigin();
            if (StringUtil.isNotBlank(origin)) {
                // 按调用方统计
                StatisticNode originNode = ClusterBuilderSlot.getOriginNode(origin, resourceWrapper.getName());
                if (originNode != null) {
                    originNode.addPassRequest(count);
                }
            }
            
            // 全局统计
            Constants.ENTRY_NODE.increaseThreadNum();
            Constants.ENTRY_NODE.addPassRequest(count);
        }
        
        /**
         * 记录完成统计
         */
        private void recordComplete(ResourceWrapper resourceWrapper, int count, 
                                  Object... args, long rt) {
            // 更新响应时间统计
            ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(resourceWrapper.getName());
            if (clusterNode != null) {
                clusterNode.addRt(rt);
                clusterNode.addSuccessRequest(count);
            }
            
            // 减少线程数
            Constants.ENTRY_NODE.decreaseThreadNum();
        }
    }
    
    /**
     * FlowSlot:流量控制Slot
     */
    public static class FlowSlot extends AbstractLinkedProcessorSlot<Object> {
        
        private final FlowRuleChecker checker = new FlowRuleChecker();
        
        @Override
        public void entry(Context context, ResourceWrapper resourceWrapper, 
                        Object param, int count, boolean prioritized, Object... args) throws Throwable {
            
            // 1. 检查流控规则
            checker.checkFlow(resourceWrapper, context, param, count, prioritized);
            
            // 2. 执行后续Slot
            fireEntry(context, resourceWrapper, param, count, prioritized, args);
        }
    }
    
    /**
     * 流量规则检查器
     */
    public static class FlowRuleChecker {
        
        public void checkFlow(ResourceWrapper resource, Context context, 
                            Object param, int count, boolean prioritized) throws BlockException {
            
            // 1. 获取资源的流控规则
            List<FlowRule> rules = FlowRuleManager.getRulesForResource(resource.getName());
            if (rules == null || rules.isEmpty()) {
                return; // 无规则,直接通过
            }
            
            // 2. 按优先级排序
            rules.sort((o1, o2) -> {
                int p1 = o1.getStrategy();
                int p2 = o2.getStrategy();
                return Integer.compare(p1, p2);
            });
            
            // 3. 依次检查规则
            for (FlowRule rule : rules) {
                if (!canPassCheck(rule, context, param, count)) {
                    // 触发流控
                    String limitApp = rule.getLimitApp();
                    throw new FlowException(rule.getLimitApp(), rule);
                }
            }
        }
        
        /**
         * 检查单个规则
         */
        private boolean canPassCheck(FlowRule rule, Context context, 
                                   Object param, int count) {
            String limitApp = rule.getLimitApp();
            
            // 检查限流应用
            if (!rule.getLimitApp().equals(limitApp) && 
                !RuleConstant.LIMIT_APP_DEFAULT.equals(limitApp)) {
                return true;
            }
            
            // 选择节点进行统计
            Node selectedNode = selectNodeByStrategy(rule, context);
            if (selectedNode == null) {
                return true;
            }
            
            // 根据控制行为检查
            return rule.getRater().canPass(selectedNode, count, rule);
        }
        
        /**
         * 根据策略选择节点
         */
        private Node selectNodeByStrategy(FlowRule rule, Context context) {
            String strategy = rule.getStrategy();
            
            switch (strategy) {
                case RuleConstant.STRATEGY_DIRECT:
                    // 直接限流:针对当前资源
                    return ClusterBuilderSlot.getClusterNode(rule.getResource());
                    
                case RuleConstant.STRATEGY_RELATE:
                    // 关联限流:针对关联资源
                    String refResource = rule.getRefResource();
                    return ClusterBuilderSlot.getClusterNode(refResource);
                    
                case RuleConstant.STRATEGY_CHAIN:
                    // 链路限流:针对入口资源
                    String entryResource = rule.getRefResource();
                    if (context.getCurEntry() != null && 
                        context.getCurEntry().getResourceWrapper().getName().equals(entryResource)) {
                        return context.getCurNode();
                    }
                    return null;
                    
                default:
                    return null;
            }
        }
    }
}

⚖️ 三、QPS vs 并发数:两种限流模式深度对比

💡 两种限流模式的本质差异

QPS与并发数限流的核心区别

java 复制代码
/**
 * QPS vs 并发数限流深度对比
 * 从原理到实现的全面分析
 */
@Component
@Slf4j
public class QpsVsConcurrencyComparison {
    
    /**
     * 两种限流模式对比
     */
    @Data
    @Builder
    public static class Comparison {
        private final String dimension;          // 维度
        private final QpsLimiter qps;           // QPS限流
        private final ConcurrencyLimiter concurrency; // 并发数限流
        private final String technicalInsight;  // 技术洞察
        
        public static List<Comparison> generate() {
            return Arrays.asList(
                Comparison.builder()
                    .dimension("限流目标")
                    .qps(QpsLimiter.builder()
                        .target("控制单位时间内的请求数量")
                        .focus("请求频率控制")
                        .metric("请求/秒")
                        .goal("防止系统过载,平滑流量")
                        .build())
                    .concurrency(ConcurrencyLimiter.builder()
                        .target("控制同时处理的请求数量")
                        .focus("资源使用控制")
                        .metric("并发线程数")
                        .goal("防止资源耗尽,保护系统稳定")
                        .build())
                    .technicalInsight("""
                        本质区别:
                        - QPS限流:控制"速率",关注单位时间内的请求数
                        - 并发数限流:控制"并发度",关注同时处理的请求数
                        
                        类比:
                        - QPS:高速公路的车辆通过速率(辆/小时)
                        - 并发数:高速公路上的同时行驶车辆数
                        """)
                    .build(),
                    
                Comparison.builder()
                    .dimension("实现原理")
                    .qps(QpsLimiter.builder()
                        .principle("""
                            基于时间窗口的计数
                            1. 固定窗口计数器
                            2. 滑动窗口计数器
                            3. 令牌桶算法
                            4. 漏桶算法
                            """)
                        .algorithm("""
                            // 滑动窗口计数器示例
                            public class SlidingWindow {
                                // 窗口分成多个小格子
                                private AtomicLong[] timeSlots;
                                private long windowSize;  // 窗口大小(ms)
                                private int slotCount;    // 格子数量
                                
                                public synchronized boolean tryAcquire() {
                                    long now = System.currentTimeMillis();
                                    long windowStart = now - windowSize;
                                    
                                    // 清理过期格子
                                    clearExpiredSlots(windowStart);
                                    
                                    // 统计窗口内请求数
                                    long count = getCountInWindow(windowStart, now);
                                    
                                    if (count < threshold) {
                                        // 记录当前请求
                                        recordRequest(now);
                                        return true;
                                    }
                                    return false;
                                }
                            }
                            """)
                        .build())
                    .concurrency(ConcurrencyLimiter.builder()
                        .principle("""
                            基于信号量的控制
                            1. 计数信号量
                            2. 线程池大小
                            3. 数据库连接池
                            """)
                        .algorithm("""
                            // 信号量实现示例
                            public class SemaphoreLimiter {
                                private final Semaphore semaphore;
                                private final int maxConcurrency;
                                
                                public SemaphoreLimiter(int maxConcurrency) {
                                    this.maxConcurrency = maxConcurrency;
                                    this.semaphore = new Semaphore(maxConcurrency);
                                }
                                
                                public boolean tryAcquire() {
                                    return semaphore.tryAcquire();
                                }
                                
                                public void release() {
                                    semaphore.release();
                                }
                                
                                // 获取当前并发数
                                public int getCurrentConcurrency() {
                                    return maxConcurrency - semaphore.availablePermits();
                                }
                            }
                            
                            // 或使用线程池
                            ExecutorService executor = Executors.newFixedThreadPool(10);
                            // 线程池本身就是一个并发限制器
                            """)
                        .build())
                    .technicalInsight("""
                        实现机制差异:
                        - QPS限流:需要时间维度统计,实现相对复杂
                        - 并发数限流:基于资源计数,实现相对简单
                        
                        性能影响:
                        - QPS限流:统计开销主要在计数和窗口管理
                        - 并发数限流:上下文切换和线程管理开销
                        """)
                    .build(),
                    
                Comparison.builder()
                    .dimension("适用场景")
                    .qps(QpsLimiter.builder()
                        .scenarios("""
                            1. API限流
                               - 防止API被过度调用
                               - 保护后端服务
                               
                            2. 爬虫控制
                               - 限制爬虫频率
                               - 防止数据被抓取
                               
                            3. 秒杀活动
                               - 控制秒杀请求频率
                               - 平滑突发流量
                               
                            4. 第三方接口调用
                               - 遵守第三方接口调用限制
                               - 避免被限流
                            """)
                        .advantages("""
                            1. 精确控制请求频率
                            2. 平滑流量,避免突发
                            3. 易于理解和配置
                            """)
                        .limitations("""
                            1. 无法限制长时间运行的任务
                            2. 对资源占用的控制较弱
                            3. 突发流量可能被拒绝
                            """)
                        .build())
                    .concurrency(ConcurrencyLimiter.builder()
                        .scenarios("""
                            1. 数据库连接保护
                               - 防止连接池耗尽
                               - 避免数据库过载
                               
                            2. 线程池保护
                               - 控制并发线程数
                               - 避免线程耗尽
                               
                            3. 慢查询保护
                               - 防止慢查询占用所有连接
                               - 保证系统响应性
                               
                            4. 资源敏感操作
                               - 大文件上传/下载
                               - 复杂计算任务
                               - 外部服务调用
                            """)
                        .advantages("""
                            1. 直接保护系统资源
                            2. 防止慢请求堆积
                            3. 避免资源耗尽
                            """)
                        .limitations("""
                            1. 无法控制请求频率
                            2. 可能造成请求排队
                            3. 配置不当可能导致饥饿
                            """)
                        .build())
                    .technicalInsight("""
                        场景选择原则:
                        
                        选择QPS限流当:
                        - 需要控制请求频率
                        - 防止API被刷
                        - 遵守外部调用限制
                        
                        选择并发数限流当:
                        - 需要保护有限资源
                        - 有长时间运行的任务
                        - 防止慢请求影响系统
                        
                        最佳实践:两者结合使用
                        - 外层用QPS限流控制频率
                        - 内层用并发数限流保护资源
                        """)
                    .build()
            );
        }
    }
    
    /**
     * Sentinel中的QPS限流实现
     */
    public static class SentinelQpsLimiter {
        
        /**
         * 滑动窗口计数器实现
         */
        public class SlidingWindow {
            // 窗口格子数组
            private final AtomicReferenceArray<WindowWrap> array;
            // 窗口大小(毫秒)
            private final int windowLengthInMs;
            // 采样窗口数量
            private final int sampleCount;
            // 每个格子的时长
            private final int intervalInMs;
            
            /**
             * 尝试通过
             */
            public boolean tryPass(int acquireCount, double threshold) {
                // 获取当前时间窗口
                long currentTime = TimeUtil.currentTimeMillis();
                long currentWindowStart = calculateWindowStart(currentTime);
                
                int idx = calculateWindowIdx(currentTime);
                
                // 计算窗口开始时间
                long oldWindowStart = 0L;
                WindowWrap oldWindow = array.get(idx);
                if (oldWindow != null) {
                    oldWindowStart = oldWindow.windowStart();
                    
                    if (oldWindowStart == currentWindowStart) {
                        // 当前窗口
                        long pass = oldWindow.value().addAndGet(acquireCount);
                        return pass <= threshold;
                    }
                }
                
                // 重置窗口
                WindowWrap newWindow = new WindowWrap(intervalInMs, currentWindowStart, new AtomicLong(0));
                if (array.compareAndSet(idx, oldWindow, newWindow)) {
                    long pass = newWindow.value().addAndGet(acquireCount);
                    return pass <= threshold;
                } else {
                    // 并发情况,重试
                    Thread.yield();
                    return tryPass(acquireCount, threshold);
                }
            }
            
            /**
             * 获取窗口内总请求数
             */
            public long getWindowPass(long currentTime) {
                long sum = 0L;
                for (int i = 0; i < array.length(); i++) {
                    WindowWrap w = array.get(i);
                    if (w != null && isWindowDeprecated(currentTime, w)) {
                        sum += w.value().get();
                    }
                }
                return sum;
            }
            
            /**
             * 计算窗口索引
             */
            private int calculateWindowIdx(long timeMillis) {
                long timeId = timeMillis / intervalInMs;
                return (int)(timeId % array.length());
            }
            
            /**
             * 计算窗口开始时间
             */
            private long calculateWindowStart(long timeMillis) {
                return timeMillis - timeMillis % intervalInMs;
            }
            
            /**
             * 判断窗口是否过期
             */
            private boolean isWindowDeprecated(long currentTime, WindowWrap windowWrap) {
                return currentTime - windowWrap.windowStart() <= windowLengthInMs;
            }
        }
        
        /**
         * 窗口包装类
         */
        public static class WindowWrap {
            private final long windowLengthInMs;
            private long windowStart;
            private AtomicLong value;
            
            public WindowWrap(long windowLengthInMs, long windowStart, AtomicLong value) {
                this.windowLengthInMs = windowLengthInMs;
                this.windowStart = windowStart;
                this.value = value;
            }
            
            public long windowStart() {
                return windowStart;
            }
            
            public AtomicLong value() {
                return value;
            }
        }
    }
    
    /**
     * Sentinel中的并发数限流实现
     */
    public static class SentinelConcurrencyLimiter {
        
        /**
         * 并发数限流器
         */
        public class ConcurrencyLimiter {
            // 最大并发数
            private final int maxConcurrency;
            // 当前并发数
            private final AtomicInteger currentConcurrency = new AtomicInteger(0);
            // 等待队列
            private final Queue<RequestContext> waitingQueue = new ConcurrentLinkedQueue<>();
            // 超时时间
            private final long timeoutInMs;
            
            /**
             * 尝试获取许可
             */
            public boolean tryAcquire(RequestContext context) {
                long startTime = System.currentTimeMillis();
                
                while (true) {
                    int current = currentConcurrency.get();
                    
                    if (current >= maxConcurrency) {
                        // 并发数已满,检查是否等待
                        if (context.getTimeoutInMs() <= 0) {
                            return false; // 不等待,直接失败
                        }
                        
                        // 加入等待队列
                        waitingQueue.offer(context);
                        
                        // 计算剩余等待时间
                        long elapsed = System.currentTimeMillis() - startTime;
                        long remaining = context.getTimeoutInMs() - elapsed;
                        
                        if (remaining <= 0) {
                            waitingQueue.remove(context);
                            return false; // 等待超时
                        }
                        
                        // 等待
                        try {
                            synchronized (context) {
                                context.wait(remaining);
                            }
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            waitingQueue.remove(context);
                            return false;
                        }
                        
                        // 被唤醒,重试
                        continue;
                    }
                    
                    // 尝试增加并发数
                    if (currentConcurrency.compareAndSet(current, current + 1)) {
                        context.setAcquired(true);
                        return true;
                    }
                    
                    // CAS失败,重试
                    Thread.yield();
                }
            }
            
            /**
             * 释放许可
             */
            public void release() {
                int current = currentConcurrency.decrementAndGet();
                
                // 唤醒等待队列中的请求
                if (!waitingQueue.isEmpty() && current < maxConcurrency) {
                    RequestContext context = waitingQueue.poll();
                    if (context != null) {
                        synchronized (context) {
                            context.notify();
                        }
                    }
                }
            }
        }
        
        /**
         * 请求上下文
         */
        public static class RequestContext {
            private final long timeoutInMs;
            private volatile boolean acquired = false;
            
            public RequestContext(long timeoutInMs) {
                this.timeoutInMs = timeoutInMs;
            }
            
            public long getTimeoutInMs() {
                return timeoutInMs;
            }
            
            public boolean isAcquired() {
                return acquired;
            }
            
            public void setAcquired(boolean acquired) {
                this.acquired = acquired;
            }
        }
    }
    
    /**
     * 组合限流策略
     */
    public class CombinedLimiter {
        // QPS限流器
        private final SentinelQpsLimiter.SlidingWindow qpsLimiter;
        // 并发数限流器
        private final SentinelConcurrencyLimiter.ConcurrencyLimiter concurrencyLimiter;
        
        public CombinedLimiter(int qpsThreshold, int concurrencyThreshold) {
            this.qpsLimiter = new SentinelQpsLimiter.SlidingWindow();
            this.concurrencyLimiter = new SentinelConcurrencyLimiter.ConcurrencyLimiter(concurrencyThreshold);
        }
        
        /**
         * 双重检查
         */
        public boolean tryAcquire() {
            // 1. 先检查QPS
            if (!qpsLimiter.tryPass(1, qpsThreshold)) {
                return false; // QPS超限
            }
            
            // 2. 再检查并发数
            RequestContext context = new RequestContext(100); // 100ms超时
            if (!concurrencyLimiter.tryAcquire(context)) {
                return false; // 并发数超限
            }
            
            return true;
        }
        
        /**
         * 释放
         */
        public void release() {
            concurrencyLimiter.release();
        }
    }
}

🔥 四、热点参数限流:精准控制的智慧

💡 热点参数限流的设计思想

热点参数识别与差异化限流
热点检测流程


热点识别算法
滑动计数窗口
Top-N 统计
频次阈值检测
时间衰减因子
热点参数示例
商品ID: 12345
用户ID: 67890
IP地址: 192.168.1.1
请求进入
提取请求参数
参数识别
普通参数
热点参数
普通限流规则
热点参数检测
参数统计器
滑动窗口统计
热点检测算法
是否为热点?
应用热点限流规则
应用普通限流规则
统一限流
差异化限流
通过/拒绝

🔧 热点参数限流实现深度解析

java 复制代码
/**
 * 热点参数限流深度解析
 * 包含热点检测、参数统计、差异化限流
 */
@Component
@Slf4j
public class HotParamLimiterDeepDive {
    
    /**
     * 热点参数限流规则
     */
    @Data
    public class HotParamRule {
        // 资源名
        private String resource;
        // 参数索引(0表示第一个参数)
        private Integer paramIdx;
        // 限流阈值
        private double count;
        // 统计窗口时长(毫秒)
        private long durationInSec = 1;
        // 热点参数类型
        private Class<?> paramClass;
        // 是否启用热点检测
        private boolean hotDetectionEnabled = true;
        // 热点检测阈值
        private int hotDetectionThreshold = 100;
        // 热点检测窗口大小
        private int hotDetectionWindow = 10;
        // 差异化限流规则
        private Map<Object, Double> specificRules = new HashMap<>();
        
        /**
         * 获取参数的限流阈值
         */
        public double getThresholdForParam(Object paramValue) {
            // 1. 检查是否有特定规则
            if (specificRules.containsKey(paramValue)) {
                return specificRules.get(paramValue);
            }
            
            // 2. 检查是否为热点参数
            if (hotDetectionEnabled && isHotParam(paramValue)) {
                // 热点参数使用更严格的限制
                return count * 0.5; // 热点参数限流减半
            }
            
            // 3. 默认规则
            return count;
        }
        
        /**
         * 检测是否为热点参数
         */
        private boolean isHotParam(Object paramValue) {
            // 从统计器中获取参数统计
            ParamMetric metric = getParamMetric(paramValue);
            if (metric == null) {
                return false;
            }
            
            // 检查是否超过热点阈值
            long passQps = metric.passQps();
            return passQps > hotDetectionThreshold;
        }
        
        /**
         * 添加特定参数规则
         */
        public void addSpecificRule(Object paramValue, double threshold) {
            specificRules.put(paramValue, threshold);
        }
    }
    
    /**
     * 参数统计器
     */
    public class ParamMetric {
        // 参数值
        private final Object paramValue;
        // 滑动窗口统计器
        private final SlidingWindowCounter counter;
        // 最后访问时间
        private volatile long lastAccessTime;
        // 是否为热点
        private volatile boolean isHot = false;
        // 热度分数
        private volatile double hotScore = 0.0;
        
        public ParamMetric(Object paramValue, int windowLength, int interval) {
            this.paramValue = paramValue;
            this.counter = new SlidingWindowCounter(windowLength, interval);
            this.lastAccessTime = System.currentTimeMillis();
        }
        
        /**
         * 增加通过计数
         */
        public void addPass(int count) {
            counter.addPass(count);
            lastAccessTime = System.currentTimeMillis();
            updateHotScore();
        }
        
        /**
         * 增加阻塞计数
         */
        public void addBlock(int count) {
            counter.addBlock(count);
        }
        
        /**
         * 获取QPS
         */
        public long passQps() {
            return counter.passQps();
        }
        
        /**
         * 获取总请求数
         */
        public long totalRequests() {
            return counter.totalRequests();
        }
        
        /**
         * 更新热度分数
         */
        private void updateHotScore() {
            long currentTime = System.currentTimeMillis();
            long elapsed = currentTime - lastAccessTime;
            
            // 热度衰减算法
            if (elapsed > 1000) { // 1秒衰减
                hotScore *= Math.exp(-elapsed / 1000.0); // 指数衰减
            }
            
            // 增加当前请求的热度
            hotScore += 1.0;
            
            // 判断是否为热点
            isHot = hotScore > 100; // 阈值可配置
        }
        
        /**
         * 获取热度分数
         */
        public double getHotScore() {
            return hotScore;
        }
        
        public boolean isHot() {
            return isHot;
        }
    }
    
    /**
     * 热点参数限流控制器
     */
    public class HotParamFlowController {
        // 参数统计器映射
        private final ConcurrentMap<Object, ParamMetric> paramMetrics = 
            new ConcurrentHashMap<>();
        // 规则映射
        private final ConcurrentMap<String, HotParamRule> rules = 
            new ConcurrentHashMap<>();
        // 热点检测器
        private final HotParamDetector detector;
        // 清理任务
        private final ScheduledExecutorService cleanupExecutor;
        
        public HotParamFlowController() {
            this.detector = new HotParamDetector(this);
            this.cleanupExecutor = Executors.newSingleThreadScheduledExecutor(
                r -> new Thread(r, "hot-param-cleanup"));
            
            // 定期清理过期参数
            cleanupExecutor.scheduleAtFixedRate(
                this::cleanupExpiredParams, 1, 1, TimeUnit.MINUTES);
            
            // 启动热点检测
            detector.start();
        }
        
        /**
         * 检查请求是否通过
         */
        public boolean canPass(String resource, Object[] args, HotParamRule rule) {
            if (args == null || args.length <= rule.getParamIdx()) {
                return true; // 参数不足,直接通过
            }
            
            Object paramValue = args[rule.getParamIdx()];
            if (paramValue == null) {
                return true; // 参数为空,直接通过
            }
            
            // 获取参数统计器
            ParamMetric metric = getOrCreateMetric(paramValue, rule);
            
            // 获取该参数的限流阈值
            double threshold = rule.getThresholdForParam(paramValue);
            
            // 检查是否超过阈值
            long passQps = metric.passQps();
            if (passQps >= threshold) {
                // 限流
                metric.addBlock(1);
                return false;
            }
            
            // 通过
            metric.addPass(1);
            return true;
        }
        
        /**
         * 获取或创建参数统计器
         */
        private ParamMetric getOrCreateMetric(Object paramValue, HotParamRule rule) {
            return paramMetrics.computeIfAbsent(paramValue, k -> 
                new ParamMetric(
                    paramValue, 
                    (int) (rule.getDurationInSec() * 1000), 
                    1000 // 1秒一个窗口
                )
            );
        }
        
        /**
         * 清理过期参数
         */
        private void cleanupExpiredParams() {
            long now = System.currentTimeMillis();
            long expireTime = 5 * 60 * 1000; // 5分钟过期
            
            Iterator<Map.Entry<Object, ParamMetric>> it = paramMetrics.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<Object, ParamMetric> entry = it.next();
                ParamMetric metric = entry.getValue();
                
                if (now - metric.lastAccessTime > expireTime) {
                    it.remove();
                    log.debug("Cleaned up expired param metric: {}", entry.getKey());
                }
            }
        }
        
        /**
         * 获取热点参数列表
         */
        public List<Map.Entry<Object, Double>> getHotParams(int topN) {
            List<Map.Entry<Object, Double>> hotParams = new ArrayList<>();
            
            for (Map.Entry<Object, ParamMetric> entry : paramMetrics.entrySet()) {
                if (entry.getValue().isHot()) {
                    hotParams.add(new AbstractMap.SimpleEntry<>(
                        entry.getKey(), 
                        entry.getValue().getHotScore()
                    ));
                }
            }
            
            // 按热度排序
            hotParams.sort((a, b) -> Double.compare(b.getValue(), a.getValue()));
            
            // 返回TopN
            return hotParams.subList(0, Math.min(topN, hotParams.size()));
        }
    }
    
    /**
     * 热点参数检测器
     */
    public class HotParamDetector {
        private final HotParamFlowController controller;
        private final ScheduledExecutorService detectorExecutor;
        private volatile boolean running = false;
        
        public HotParamDetector(HotParamFlowController controller) {
            this.controller = controller;
            this.detectorExecutor = Executors.newSingleThreadScheduledExecutor(
                r -> new Thread(r, "hot-param-detector"));
        }
        
        public void start() {
            if (running) {
                return;
            }
            running = true;
            
            // 每10秒检测一次热点
            detectorExecutor.scheduleAtFixedRate(
                this::detectHotParams, 10, 10, TimeUnit.SECONDS);
        }
        
        public void stop() {
            running = false;
            detectorExecutor.shutdown();
        }
        
        /**
         * 检测热点参数
         */
        private void detectHotParams() {
            try {
                // 获取热点参数
                List<Map.Entry<Object, Double>> hotParams = controller.getHotParams(10);
                
                if (!hotParams.isEmpty()) {
                    log.info("Detected hot params: {}", hotParams);
                    
                    // 可以在这里触发告警或自动调整规则
                    triggerHotParamAlert(hotParams);
                }
            } catch (Exception e) {
                log.error("Error detecting hot params", e);
            }
        }
        
        /**
         * 触发热点参数告警
         */
        private void triggerHotParamAlert(List<Map.Entry<Object, Double>> hotParams) {
            // 发送告警
            AlertMessage alert = AlertMessage.builder()
                .type("HOT_PARAM_ALERT")
                .level("WARNING")
                .title("热点参数检测告警")
                .content(String.format("检测到%d个热点参数", hotParams.size()))
                .details(hotParams)
                .timestamp(System.currentTimeMillis())
                .build();
            
            // 发送到告警系统
            alertService.sendAlert(alert);
            
            // 可以自动调整限流规则
            adjustRulesForHotParams(hotParams);
        }
        
        /**
         * 为热点参数调整规则
         */
        private void adjustRulesForHotParams(List<Map.Entry<Object, Double>> hotParams) {
            for (Map.Entry<Object, Double> entry : hotParams) {
                Object paramValue = entry.getKey();
                double hotScore = entry.getValue();
                
                // 根据热度调整限流阈值
                double newThreshold = calculateNewThreshold(hotScore);
                
                // 更新规则
                updateRuleForParam(paramValue, newThreshold);
            }
        }
        
        /**
         * 计算新的限流阈值
         */
        private double calculateNewThreshold(double hotScore) {
            // 热度越高,阈值越低(限流更严格)
            if (hotScore > 1000) {
                return 10; // 极高热度,严格限流
            } else if (hotScore > 500) {
                return 50; // 高热度,较强限流
            } else if (hotScore > 100) {
                return 100; // 中等热度,适度限流
            } else {
                return 200; // 低热度,宽松限流
            }
        }
    }
    
    /**
     * 滑动窗口计数器
     */
    public class SlidingWindowCounter {
        // 窗口长度(毫秒)
        private final int windowLengthInMs;
        // 窗口间隔(毫秒)
        private final int intervalInMs;
        // 窗口数量
        private final int windowCount;
        // 窗口数组
        private final AtomicReferenceArray<Window> windows;
        
        public SlidingWindowCounter(int windowLengthInMs, int intervalInMs) {
            this.windowLengthInMs = windowLengthInMs;
            this.intervalInMs = intervalInMs;
            this.windowCount = windowLengthInMs / intervalInMs;
            this.windows = new AtomicReferenceArray<>(windowCount);
        }
        
        /**
         * 增加通过计数
         */
        public void addPass(int count) {
            Window window = getCurrentWindow();
            window.addPass(count);
        }
        
        /**
         * 增加阻塞计数
         */
        public void addBlock(int count) {
            Window window = getCurrentWindow();
            window.addBlock(count);
        }
        
        /**
         * 获取当前窗口内的通过QPS
         */
        public long passQps() {
            long currentTime = System.currentTimeMillis();
            long windowStart = currentTime - windowLengthInMs;
            
            long passCount = 0;
            for (int i = 0; i < windowCount; i++) {
                Window window = windows.get(i);
                if (window != null && window.getStartTime() > windowStart) {
                    passCount += window.getPassCount();
                }
            }
            
            return passCount * 1000 / windowLengthInMs;
        }
        
        /**
         * 获取总请求数
         */
        public long totalRequests() {
            long total = 0;
            for (int i = 0; i < windowCount; i++) {
                Window window = windows.get(i);
                if (window != null) {
                    total += window.getTotalCount();
                }
            }
            return total;
        }
        
        /**
         * 获取当前时间窗口
         */
        private Window getCurrentWindow() {
            long currentTime = System.currentTimeMillis();
            int idx = calculateWindowIdx(currentTime);
            long windowStart = calculateWindowStart(currentTime);
            
            while (true) {
                Window oldWindow = windows.get(idx);
                if (oldWindow == null) {
                    // 创建新窗口
                    Window newWindow = new Window(windowStart);
                    if (windows.compareAndSet(idx, null, newWindow)) {
                        return newWindow;
                    } else {
                        // 并发创建,重试
                        Thread.yield();
                    }
                } else if (oldWindow.getStartTime() == windowStart) {
                    // 当前窗口
                    return oldWindow;
                } else if (oldWindow.getStartTime() < windowStart) {
                    // 旧窗口,需要重置
                    Window newWindow = new Window(windowStart);
                    if (windows.compareAndSet(idx, oldWindow, newWindow)) {
                        return newWindow;
                    } else {
                        // 并发更新,重试
                        Thread.yield();
                    }
                } else {
                    // 时间回退,理论上不会发生
                    return new Window(windowStart);
                }
            }
        }
        
        private int calculateWindowIdx(long timeMillis) {
            long timeId = timeMillis / intervalInMs;
            return (int)(timeId % windowCount);
        }
        
        private long calculateWindowStart(long timeMillis) {
            return timeMillis - timeMillis % intervalInMs;
        }
        
        /**
         * 时间窗口
         */
        private static class Window {
            private final long startTime;
            private final AtomicLong passCount = new AtomicLong(0);
            private final AtomicLong blockCount = new AtomicLong(0);
            
            public Window(long startTime) {
                this.startTime = startTime;
            }
            
            public void addPass(int count) {
                passCount.addAndGet(count);
            }
            
            public void addBlock(int count) {
                blockCount.addAndGet(count);
            }
            
            public long getPassCount() {
                return passCount.get();
            }
            
            public long getBlockCount() {
                return blockCount.get();
            }
            
            public long getTotalCount() {
                return passCount.get() + blockCount.get();
            }
            
            public long getStartTime() {
                return startTime;
            }
        }
    }
    
    /**
     * 热点参数限流使用示例
     */
    @RestController
    @RequestMapping("/api/products")
    public class ProductController {
        
        @Autowired
        private HotParamFlowController hotParamController;
        
        /**
         * 热点商品查询接口
         * 对商品ID进行热点参数限流
         */
        @GetMapping("/{productId}")
        @SentinelResource(
            value = "getProductDetail",
            blockHandler = "handleBlock",
            fallback = "handleFallback"
        )
        public ProductDetail getProductDetail(@PathVariable Long productId,
                                             @RequestParam(required = false) String userId) {
            
            // 1. 检查热点参数限流
            HotParamRule rule = new HotParamRule();
            rule.setResource("getProductDetail");
            rule.setParamIdx(0); // 第一个参数:productId
            rule.setCount(100); // 默认QPS限制
            rule.setDurationInSec(1);
            
            // 2. 为特定热点商品设置更严格的限制
            if (isHotProduct(productId)) {
                rule.addSpecificRule(productId, 10.0); // 热点商品限制10QPS
            }
            
            // 3. 检查是否通过
            Object[] args = {productId, userId};
            if (!hotParamController.canPass("getProductDetail", args, rule)) {
                throw new RateLimitException("商品访问频率过高,请稍后重试");
            }
            
            // 4. 执行业务逻辑
            return productService.getProductDetail(productId);
        }
        
        /**
         * 订单创建接口
         * 对用户ID进行热点参数限流
         */
        @PostMapping("/orders")
        public Order createOrder(@RequestBody CreateOrderRequest request) {
            
            // 1. 热点参数:用户ID
            HotParamRule userRule = new HotParamRule();
            userRule.setResource("createOrder");
            userRule.setParamIdx(0); // 用户ID
            userRule.setCount(50); // 默认限制
            
            // 2. 热点参数:商品ID
            HotParamRule productRule = new HotParamRule();
            productRule.setResource("createOrder");
            productRule.setParamIdx(1); // 商品ID
            productRule.setCount(100); // 默认限制
            
            // 3. 双重检查
            Object[] args = {request.getUserId(), request.getProductId()};
            if (!hotParamController.canPass("createOrder", args, userRule) ||
                !hotParamController.canPass("createOrder", args, productRule)) {
                throw new RateLimitException("操作过于频繁,请稍后重试");
            }
            
            // 4. 执行业务逻辑
            return orderService.createOrder(request);
        }
        
        /**
         * 热点商品检测
         */
        private boolean isHotProduct(Long productId) {
            // 这里可以实现热点商品检测逻辑
            // 例如:从缓存中获取商品热度
            String cacheKey = "hot:product:" + productId;
            Integer hotScore = redisTemplate.opsForValue().get(cacheKey);
            return hotScore != null && hotScore > 100;
        }
        
        /**
         * 阻塞处理器
         */
        public ProductDetail handleBlock(Long productId, String userId, BlockException ex) {
            log.warn("商品详情接口被限流,productId: {}, userId: {}", productId, userId);
            
            // 返回兜底数据
            ProductDetail fallback = new ProductDetail();
            fallback.setProductId(productId);
            fallback.setProductName("商品详情暂时不可用");
            fallback.setAvailable(false);
            fallback.setFallback(true);
            return fallback;
        }
        
        /**
         * 降级处理器
         */
        public ProductDetail handleFallback(Long productId, String userId, Throwable t) {
            log.error("商品详情接口降级,productId: {}, userId: {}", productId, userId, t);
            
            // 返回降级数据
            ProductDetail fallback = new ProductDetail();
            fallback.setProductId(productId);
            fallback.setProductName("服务暂时不可用,请稍后重试");
            fallback.setAvailable(false);
            fallback.setFallback(true);
            return fallback;
        }
    }
}

思考 :Sentinel的流量控制哲学已经从传统的"被动防御"演进为"主动治理"。记住三个核心认知:1) SlotChain不是简单的过滤器链,而是可插拔的治理框架 ,每个Slot都是一个治理维度;2) QPS和并发数限流解决的是不同维度的问题 ,QPS控制"速率",并发数控制"资源";3) 热点参数限流的本质是精准的资源分配 ,让有限的系统资源服务更多的用户。真正的流量治理不是简单地拒绝请求,而是智能地分配请求,优雅地降级服务,动态地调整策略


如果觉得本文对你有帮助,请点击 👍 点赞 + ⭐ 收藏 + 💬 留言支持!

讨论话题

  1. 你在项目中是如何使用Sentinel进行流量治理的?
  2. 如何选择合适的限流算法?
  3. 热点参数限流有哪些最佳实践?

相关资源推荐


相关推荐
运维开发小白2 小时前
服务发现中间件ConSul的操作指南
中间件·服务发现·consul
阿里云云原生2 小时前
RUM 助力 iOS 应用稳定性:从异常捕获到堆栈还原的全流程分析
人工智能·阿里云·ios·云原生·rum
VermiliEiz2 小时前
二进制文件方式部署k8s(3)
云原生·容器·kubernetes·containerd
‿hhh3 小时前
微服务智慧交通管理平台 - 项目实现(结合Qoder搭建)
java·人工智能·机器学习·微服务·架构·需求分析·规格说明书
企鹅侠客13 小时前
使用k8s集群调度GPU
云原生·容器·kubernetes
zcz160712782115 小时前
k8s重新部署的配置过程
云原生·容器·kubernetes
程序员zgh16 小时前
C语言 指针用法与区别(指针常量、常量指针、指针函数、函数指针、二级指针)
c语言·开发语言·jvm·c++
没有bug.的程序员16 小时前
熔断、降级、限流:高可用架构的三道防线
java·网络·jvm·微服务·架构·熔断·服务注册
阿里云云原生17 小时前
加入我们,一起定义「Data x AI」的未来
云原生