【手撕系列】Java限流算法详解下篇:漏桶与令牌桶算法实现!(建议收藏)

🔥 本文是限流算法系列的下篇,将带你深入理解漏桶和令牌桶限流算法。从原理到代码实现,从单机到分布式,全方位掌握这两种高级限流技术。

📚 博主匠心之作,强推专栏

在这里插入图片描述

一、漏桶算法详解

1.1 算法原理

还记得小时候去农村,看到房顶用水桶接雨水的场景吗?漏桶算法的思想其实和这个很像。

1. 漏桶模型

想象一个水桶:

  • 上面有个口子不断接收水(请求)
  • 下面有个小孔以固定速率漏水(处理)
  • 桶有容量限制,装不下就溢出(拒绝)

拿我们系统的消息推送来举例:

  • 上游服务疯狂发消息(可能一秒几千条)
  • 我们的推送接口限制固定速率(每秒100条)
  • 超出的消息先放桶里(缓冲区)
  • 桶满了就拒绝新消息(限流)
2. 水流速率

这个是漏桶最关键的参数。还是拿消息推送举例:

  • 我们发现每秒处理100条是比较合适的
  • 再快,服务器扛不住
  • 再慢,消息延迟太大
  • 所以设定漏桶速率就是100/秒

实际使用中要注意:

  • 速率要根据系统承载能力来定
  • 要留点余量,不能踩着极限值
  • 最好能动态调整,应对流量变化
3. 桶容量设计

这个要根据实际场景权衡。我们系统最开始设置了1000:

  • 优点是可以应对短时高峰
  • 缺点是消息延迟可能变大
  • 后来改成了500,在延迟和承载间取了个平衡

几个实践建议:

  • 容量太大,延迟会变高
  • 容量太小,缓冲作用就没了
  • 建议设置告警阈值(比如80%)
  • 监控桶的使用率,方便调优

漏桶算法最大的特点就是"恒定速率"。这在很多场景下是把双刃剑:

  • 好处是保护系统,流量非常平稳
  • 坏处是不能应对突发流量,全都得排队

所以,如果你的系统需要处理突发流量(比如秒杀),可能令牌桶算法更合适。这个我们在后面会详细讲。

1.2 漏桶算法实现

下面是一个生产级别的漏桶限流器实现:

/**
 * 漏桶限流器
 * 以固定速率处理请求,多余的请求放入桶中排队
 */
public class LeakyBucket {
   
   
    // 桶的容量(最大排队数)
    private final int capacity;
    // 漏水速率(每秒处理数)
    private final double rate;
    // 上次漏水时间
    private long lastLeakTime;
    // 当前桶中水量(待处理请求数)
    private double water;
    
    private final ReentrantLock lock = new ReentrantLock();
    
    /**
     * 创建漏桶限流器
     *
     * @param capacity 桶容量
     * @param rate     漏水速率(每秒)
     */
    public LeakyBucket(int capacity, double rate) {
   
   
        this.capacity = capacity;
        this.rate = rate;
        this.lastLeakTime = System.currentTimeMillis();
        this.water = 0;
    }
    
    /**
     * 尝试加入请求到漏桶
     * 
     * @return true:请求被接受 false:请求被拒绝
     */
    public boolean tryAcquire() {
   
   
        lock.lock();
        try {
   
   
            // 计算当前水量
            long now = System.currentTimeMillis();
            // 距离上次漏水的时间(秒)
            double timeElapsed = (now - lastLeakTime) / 1000.0;
            // 计算漏掉的水量
            double leakedWater = timeElapsed * rate;
            // 更新当前水量
            water = Math.max(0, water - leakedWater);
            lastLeakTime = now;
            
            // 如果桶未满,接受请求
            if (water < capacity) {
   
   
                water++;
                return true;
            }
            
            return false;
        } finally {
   
   
            lock.unlock();
        }
    }
    
    /**
     * 尝试加入请求,如果桶满则等待
     * 
     * @param timeout 最大等待时间(毫秒)
     * @return true:请求被接受 false:等待超时
     */
    public boolean tryAcquireWithTimeout(long timeout) {
   
   
        long endTime = System.currentTimeMillis() + timeout;
        
        while (System.currentTimeMillis() < endTime) {
   
   
            if (tryAcquire()) {
   
   
                return true;
            }
            // 等待一小段时间再试
            try {
   
   
                Thread.sleep(10);
            } catch (InterruptedException e) {
   
   
                Thread.currentThread().interrupt();
                return false;
            }
        }
        
        return false;
    }
    
    /**
     * 获取当前桶中水量
     */
    public double getCurrentWater() {
   
   
        lock.lock();
        
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值