目录

面试基础-高并发高可用架构深度实践限流算法令牌桶-vs-漏桶设计与实现

面试基础—高并发高可用架构深度实践:限流算法(令牌桶 vs 漏桶)设计与实现

高并发高可用架构深度实践:限流算法(令牌桶 vs 漏桶)设计与实现

引言:从双十一洪峰看限流的重要性

在2023年阿里双十一购物节中,核心交易系统成功支撑了每秒58.3万笔的订单创建峰值。在这背后,限流算法作为系统稳定的最后一道防线,发挥了关键作用。本文将深入探讨令牌桶与漏桶算法,结合Sentinel源码解析,揭示高并发场景下的限流实现细节。


一、限流算法核心原理

1.1 令牌桶算法

1.1.1 算法原理
  • 以恒定速率向桶中添加令牌
  • 请求到达时消耗令牌
  • 无令牌时拒绝请求

令牌生产者

令牌桶

请求消费者

添加令牌

loop

[恒定速率]

请求令牌

允许通过

拒绝请求

alt

[有可用令牌]

[无可用令牌]

令牌生产者

令牌桶

请求消费者

1.1.2 生产级实现
public class TokenBucket {
    private final AtomicLong tokens;
    private final long capacity;
    private final long refillRate; // 令牌/秒
    private volatile long lastRefillTime;
    
    public boolean tryAcquire(int permits) {
        refillTokens();
        long currentTokens = tokens.get();
        if (currentTokens < permits) {
            return false;
        }
        return tokens.compareAndSet(currentTokens, currentTokens - permits);
    }
    
    private void refillTokens() {
        long now = System.nanoTime();
        long duration = now - lastRefillTime;
        long newTokens = duration * refillRate / 1_000_000_000;
        if (newTokens > 0) {
            lastRefillTime = now;
            tokens.updateAndGet(current -> Math.min(capacity, current + newTokens));
        }
    }
}

1.2 漏桶算法

1.2.1 算法原理
  • 请求以任意速率进入漏桶
  • 以恒定速率处理请求
  • 桶满时拒绝请求

请求生产者

漏桶

请求处理器

提交请求

接受请求

拒绝请求

alt

[桶未满]

[桶已满]

处理请求

loop

[恒定速率]

请求生产者

漏桶

请求处理器

1.2.2 生产级实现
public class LeakyBucket {
    private final BlockingQueue<Request> queue;
    private final int capacity;
    private final long processRate; // 请求/秒
    
    public boolean tryEnqueue(Request request) {
        return queue.offer(request);
    }
    
    @SuppressWarnings("InfiniteLoopStatement")
    public void startProcessing() {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> {
            Request request = queue.poll();
            if (request != null) {
                process(request);
            }
        }, 0, 1_000_000_000 / processRate, TimeUnit.NANOSECONDS);
    }
}

二、生产环境应用实践

2.1 淘宝交易系统限流方案

挑战

  • 瞬时峰值流量可能超过系统容量10倍
  • 需要区分核心业务和非核心业务

解决方案

  1. 采用分层限流架构
    • 网关层:漏桶算法控制全局流量
    • 服务层:令牌桶算法保护核心业务
  2. 动态限流策略
    • 基于CPU、RT等指标动态调整限流阈值
    • 核心业务预留20%冗余容量

漏桶限流

令牌桶限流

令牌桶限流

用户请求

API网关

交易服务

库存服务

支付服务

2.2 Sentinel源码解析

以Sentinel的 FlowSlot 为例:

public class FlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
    
    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, 
        int count, boolean prioritized, Object... args) throws Throwable {
        
        // 执行限流检查
        if (!flowRuleChecker.checkFlow(resourceWrapper, context, node, count, prioritized)) {
            throw new FlowException(resourceWrapper.getName(), "flow limited");
        }
        
        // 调用后续处理器
        fireEntry(context, resourceWrapper, node, count, prioritized, args);
    }
}

三、算法对比与选型指南

维度令牌桶算法漏桶算法
流量特性允许突发流量平滑输出流量
实现复杂度中等简单
适用场景需要应对突发流量的场景需要严格控制处理速率的场景
典型应用API网关、服务接口限流消息队列消费速率控制

选型建议

  1. 网关层优先选择漏桶算法
  2. 服务层优先选择令牌桶算法
  3. 混合使用实现分层限流

四、大厂面试深度追问

4.1 基础问题

  1. 令牌桶和漏桶算法的核心区别是什么?
  2. 如何实现分布式限流?
  3. 限流算法的时间复杂度是多少?

4.2 进阶问题

  1. 如何设计支持动态调整速率的限流算法?
  2. 限流算法在微服务架构中如何应用?
  3. 如何评估限流算法对系统性能的影响?

4.3 实战问题

  1. 在双十一场景下,如何设计限流策略?
  2. 如何处理限流导致的请求失败?
  3. 如何监控和优化限流效果?

五、未来演进方向

  1. AI驱动限流 :基于机器学习预测流量模式
  2. 边缘计算限流 :在CDN边缘节点实现限流
  3. 自适应限流 :根据系统负载动态调整限流策略
  4. 跨云限流 :支持多云环境统一限流策略

通过持续优化,我们正在构建支撑千万级TPS、EB级数据量的新一代限流体系,为阿里云和字节跳动的全球化业务提供坚实保障。