应用级限流-令牌桶实现方式

本文详细介绍了Guava库中的RateLimiter工具类如何实现令牌桶算法,用于限流。讨论了令牌桶的组成部分和原理,重点解析了RateLimiter的SmoothBursty和SmoothWarmingUp两种实现方式,包括令牌初始化、消费和获取的源码分析,以及它们之间的区别。同时,阐述了RateLimiter的预消费能力及其在高并发场景下的应用场景。
摘要由CSDN通过智能技术生成

ReateLimiter 官方Demo
ReateLimiter 相关文档中文版
《亿级流量网站架构核心技术》张开涛 限流详解

令牌桶限流

在这里插入图片描述
上图为令牌桶的原理图,根据原理图能够得知:

令牌桶的组成部分

1、令牌 - 生成
2、令牌 - 存放
3、令牌 - 获取

令牌桶的原理

1、令牌生成器:根据设定的令牌生成策略生成令牌,并将令牌存放至令牌存放地(令牌桶)中。

2、令牌获取器:用户请求到达,尝试从令牌桶中获取令牌,如果获取到令牌则放行,如果获取不到则根据限流规则进行友好提示。

RateLimiter:令牌桶实现工具类

RateLimiter 是 Google 开源工具包 Guava 中针对 令牌桶算法的实现工具类。

RateLimiter 简单使用案例
public class RateLimiterDemo {
   
	public static void main(String[] args) throws IOException {
   
        // 令牌获取
        // 1-阻塞获取
        block();
        // 2-非阻塞获取
        non_block();
        System.in.read();
    }

    public static void non_block() {
   
        // 令牌生成 并放入令牌桶中
        RateLimiter rateLimiter = RateLimiter.create(1.0);
        long startTime = System.currentTimeMillis();
        IntStream.rangeClosed(0,6).forEach(
                item ->{
   
                    boolean falg = rateLimiter.tryAcquire(1, TimeUnit.MILLISECONDS);
                    System.err.println("成功与否:" + falg);
                    System.err.println("消耗时间:" + (startTime - System.currentTimeMillis()));
                }
        );

    }

    public static void block() {
   

        // 令牌生成 并放入令牌桶中
        RateLimiter rateLimiter = RateLimiter.create(1.0);
        long startTime = System.currentTimeMillis();
        IntStream.rangeClosed(0,6).forEach(
                item ->{
   
                    double waiteTime = rateLimiter.acquire(1);
                    System.err.println("等待时间:" + waiteTime);
                    System.err.println("消耗时间:" + (startTime - System.currentTimeMillis()));
                }
        );
    }
}

在演示了 RateLimter 的简单使用之后,我们根据 令牌桶 算法的三个组成部分(令牌生成、令牌存放、令牌获取)对 RateLimter 简单进行源码剖析

RateLimter 原理

令牌桶算法的理解很简单。令牌生成令牌获取令牌存储,这三部分组成了令牌桶限流算法。

对于令牌桶的实现,存在两种实现方式:

  • 1、定时线程生成令牌方式
  • 2、触发更新令牌方式

定时线程生成令牌方式实现思路

  • 开辟一个空间用来存放令牌,
  • 提供一个线程用来产生令牌并放入令牌存储空间,
  • 提供一个方法,用来尝试获取空间中的令牌。

下面重点来讲讲 RateLimter 通过触发更新的方式 如何实现令牌通算法。

RateLimter 的子类 SmoothBursty 进行原理分析

在这里插入图片描述
图中重要信息如下:

  • 1、nowMicros : 记录代码运行时长

  • 2、nextFreeTicketMicros : nextFreeTicketMicros = 每个令牌生成耗时 * 已被获取的令牌数

SmoothBurstySmoothWarmingUp 类似,SmoothBursty 生成令牌的速度是恒定的,SmoothWarmingUp 在一段时间内的速度是动态的。

SmoothBursty 中:nextFreeTicketMicros = stableIntervalMicros * 已被获取的令牌数 。stableIntervalMicros 为:每个令牌生成平均耗时。

RateLimter 总体的实现方式:将令牌的生成换算成时间,通过时间轴进行划分。以程序运行作为起始,定义两个重要时间 nowMicros nextFreeTicketMicros。
nowMicros 指向当前程序运行时间点,从而根据令牌生成速率得到到目前为止,根据速率令牌桶中应该存放有的令牌数。
nextFreeTicketMicros 表示:已被使用令牌数 换算之后的时间长度。

RateLimter 使用触发更新的方式进行令牌更新,也就是当调用 RateLimter#acquire 进行令牌获取时才会进行令牌桶的相关令牌数的计算更新。而更新的比对条件:nowMicros > nextFreeTicketMicros。
而该更新条件也造就了 RateLimter 所谓的预消费能力。假设两次请求间隔1s,第一次请求就能够预消费 1s 生成的令牌数,因为在第二次请求抵达的时候所被预消费的1s的令牌数因为时间间隔被补齐,第二次请求也无需等待。

RateLimter 源码解析

以令牌的初始化,和令牌消费 作为入口进行分析。

令牌初始化(解析 SmoothBursty)

在 RateLimiter 中有4个重载的令牌生成器构造方法 RateLimiter#create

在这里插入图片描述
我们再来看看源码,比对一下这 4 个 RateLimiter#create 方法
在这里插入图片描述

通过源码的比对,能够得到,这四个令牌生成的方法,最终构造的 RateLimter 对象,分为两种。

  • SmoothWarmingUp
    平滑预热限流
  • SmoothBursty
    平滑突发限流

先来看看 SmoothWarmingUpSmoothBurstyRateLimter 的关系

在这里插入图片描述
通过查看类结构关系,能够直观的知道,RateLimter 有一个直属的子类 SmoothRteLimiter ,而 SmoothWarmingUpSmoothBursty 继承自 SmoothRteLimiter (同时也是SmoothRteLimiter 内部类)

在对 SmoothWarmingUpSmoothBursty 这两个令牌生成类进行解析前,先来简单看看他们的父类 RateLimiterSmoothRteLimiter

RateLimiter

RateLimiter 相关属性定义

  • private final SleepingStopwatch stopwatch;
    guava一个时钟,提供两种功能:获取代码运行时长 和 提供 sleep 功能。
  • private volatile Object mutexDoNotUseDirectly;
    该对象是一个锁对象,用来作为相关操作的锁对象。
    而获取锁的操作方法为 RateLimiter#mutex

再来看看 相关的方法调用

  • RateLimiter#create
    令牌生成构造方法

  • RateLimiter#acquire
    阻塞方式,获取令牌

  • RateLimiter#tryAcquire
    非阻塞方式,获取令牌

RateLimter 提供了令牌桶相关的操作方法,具体的实现由其子类完成。

SmoothRateLimiter

SmoothRateLimiter 相关属性

  • double storedPermits;
    当前存储令牌数
  • double maxPermits;
    存储最大令牌数
  • double stableIntervalMicros;
    每个令牌的稳定生成速率。例
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值