Guava RateLimiter
时间: 2025-07-18 12:15:08 浏览: 17
<think>我们讨论的是Guava RateLimiter,它是Google Guava库中提供的一个限流工具,用于控制系统的请求速率。
主要功能:通过限制单位时间内可执行的操作数量,来保护系统免受过载的影响。
实现原理:基于令牌桶算法(Token Bucket)实现。
令牌桶算法原理:
- 系统以固定的速率向桶中添加令牌(token)。
- 当有请求到来时,会尝试从桶中取出一个或多个令牌(取决于请求需要的令牌数)。
- 如果桶中有足够的令牌,则请求被允许执行,同时令牌被消耗。
- 如果桶中没有足够的令牌,则请求会被限流(等待或直接拒绝)。
Guava RateLimiter提供了两种限流模式:
1. 平滑突发限流(SmoothBursty):允许突发流量,即如果桶中有足够的令牌,可以一次性取走。
2. 平滑预热限流(SmoothWarmingUp):在系统启动时有一段预热期,逐步将分发令牌的速率提高到配置的速率,避免冷启动时系统被压垮。
下面我们分别给出使用示例,并解释代码。
首先,我们需要在项目中引入Guava依赖(以Maven为例):
```xml
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version> <!-- 请根据实际情况选择版本 -->
</dependency>
```
示例1:使用SmoothBursty(平滑突发限流)
```java
import com.google.common.util.concurrent.RateLimiter;
public class RateLimiterDemo {
public static void main(String[] args) {
// 创建一个每秒发放2个令牌的RateLimiter
RateLimiter rateLimiter = RateLimiter.create(2.0); // 每秒2个令牌,即每500毫秒一个
// 模拟处理请求
for (int i = 0; i < 5; i++) {
// 请求一个令牌,如果令牌不足则等待,直到获取到令牌
double waitTime = rateLimiter.acquire(); // 返回等待的时间(秒)
System.out.println("获取令牌成功,等待时间: " + waitTime + "秒, 执行操作" + i);
}
}
}
```
解释:
- RateLimiter.create(2.0) 创建了一个每秒产生2个令牌的限流器。
- acquire()方法会阻塞直到获取到令牌,返回值为等待的时间(以秒为单位)。
- 在循环中,我们连续获取5次令牌。由于令牌产生速率是每秒2个,所以前两次获取可能不需要等待(或等待时间很短),因为一开始桶中有令牌。后面每次获取大约需要等待0.5秒。
示例2:使用SmoothWarmingUp(平滑预热限流)
```java
import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.TimeUnit;
public class RateLimiterWarmUpDemo {
public static void main(String[] args) {
// 创建一个每秒发放5个令牌的RateLimiter,预热时间为3秒
// 在预热期内,RateLimiter每秒增加的令牌数会逐步增加,直到达到设定的速率
RateLimiter rateLimiter = RateLimiter.create(5.0, 3, TimeUnit.SECONDS);
for (int i = 0; i < 10; i++) {
double waitTime = rateLimiter.acquire();
System.out.println("获取令牌成功,等待时间: " + waitTime + "秒, 执行操作" + i);
}
}
}
```
解释:
- RateLimiter.create(5.0, 3, TimeUnit.SECONDS) 创建了一个限流器,目标速率是每秒5个令牌,预热时间为3秒。
- 在预热期间,令牌的分发速率会从慢变快,直到达到设定的速率。这样可以让系统逐渐增加负载,避免在冷启动时突然有大量请求。
另外,RateLimiter还提供了非阻塞的方法tryAcquire:
- tryAcquire():尝试获取令牌,立即返回是否成功。
- tryAcquire(int permits, long timeout, TimeUnit unit):在指定的超时时间内尝试获取令牌。
示例3:使用tryAcquire
```java
import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.TimeUnit;
public class TryAcquireDemo {
public static void main(String[] args) {
RateLimiter rateLimiter = RateLimiter.create(2.0);
if (rateLimiter.tryAcquire()) {
// 立即获取令牌成功
System.out.println("操作执行");
} else {
System.out.println("被限流");
}
// 尝试在500毫秒内获取令牌
if (rateLimiter.tryAcquire(500, TimeUnit.MILLISECONDS)) {
System.out.println("在500毫秒内获取到令牌,操作执行");
} else {
System.out.println("在500毫秒内未获取到令牌,被限流");
}
}
}
```
注意事项:
- RateLimiter是单机的限流工具,如果是分布式系统,则需要考虑分布式限流方案。
- RateLimiter不支持修改速率,如果需要动态修改速率,可以使用其setRate方法(但要注意线程安全)。
- RateLimiter会累积令牌,如果长时间没有请求,则桶中令牌会累积到上限,从而允许突发流量。
以上就是对Guava RateLimiter的简要介绍和示例。
§§相关问题§§:
1. 令牌桶算法和漏桶算法的区别是什么?
2. 如何动态调整RateLimiter的速率?
3. 在分布式系统中如何实现限流?
4. 除了Guava RateLimiter,还有哪些常用的限流工具或框架?</think>### Guava RateLimiter 详解
Guava RateLimiter 是 Google Guava 库提供的限流工具,基于令牌桶算法实现,用于控制单位时间内操作的执行速率。它能有效防止系统过载,支持突发流量和平滑限流两种模式。
#### 核心功能:
1. **平滑突发限流**:允许短时间内突发请求
2. **平滑预热限流**:系统启动时逐步增加处理速率
3. **阻塞/非阻塞获取**:支持阻塞等待或立即返回结果
#### 基础使用示例:
```java
import com.google.common.util.concurrent.RateLimiter;
public class BasicRateLimiterDemo {
public static void main(String[] args) {
// 创建每秒允许2次操作的限流器
RateLimiter rateLimiter = RateLimiter.create(2.0);
for (int i = 1; i <= 5; i++) {
// 阻塞获取令牌
double waitTime = rateLimiter.acquire();
System.out.printf("操作%d执行, 等待时间: %.2fs%n", i, waitTime);
}
}
}
```
#### 预热限流示例(冷启动保护):
```java
import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.TimeUnit;
public class WarmupRateLimiterDemo {
public static void main(String[] args) {
// 预热型限流器:3秒内从0提升到5QPS
RateLimiter rateLimiter = RateLimiter.create(5.0, 3, TimeUnit.SECONDS);
for (int i = 1; i <= 10; i++) {
System.out.printf("操作%d执行, 等待时间: %.2fs%n",
i, rateLimiter.acquire());
}
}
}
```
#### 非阻塞尝试获取令牌:
```java
import com.google.common.util.concurrent.RateLimiter;
public class NonBlockingRateLimiterDemo {
public static void main(String[] args) {
RateLimiter rateLimiter = RateLimiter.create(1.0); // 1QPS
for (int i = 1; i <= 5; i++) {
if (rateLimiter.tryAcquire()) {
System.out.println("执行操作: " + i);
} else {
System.out.println("操作被限流: " + i);
}
Thread.sleep(300); // 模拟操作间隔
}
}
}
```
#### 批量操作限流:
```java
import com.google.common.util.concurrent.RateLimiter;
public class BulkOperationDemo {
public static void main(String[] args) {
RateLimiter rateLimiter = RateLimiter.create(10.0); // 10QPS
// 批量获取3个令牌
double waitTime = rateLimiter.acquire(3);
System.out.printf("批量操作执行, 等待时间: %.2fs%n", waitTime);
}
}
```
### 关键特性解析:
1. **令牌桶算法**:
- 系统以固定速率向桶中添加令牌
- 操作执行时需获取令牌,无令牌则阻塞/拒绝
- 支持突发流量(桶中积累的令牌可一次性使用)
2. **预热机制**:
- 解决冷启动问题
- 限流器启动时逐步提升到目标速率
- 公式:`稳定间隔 = 冷启动间隔 / 3`
3. **精度控制**:
- 使用高精度Stopwatch计时(纳秒级)
- 避免传统sleep方法的精度问题
### 最佳实践:
1. 对于数据库访问等I/O操作,使用预热限流
2. 在REST API入口处添加限流保护
3. 结合tryAcquire实现优雅降级
4. 监控实际等待时间调整限流参数
### 性能注意事项:
1. 单机限流器性能极高(>1,000,000 QPS)
2. 分布式系统需结合Redis等实现集群限流
3. 避免在超高速循环中频繁创建RateLimiter实例
---
阅读全文
相关推荐




















