Skip to content

Commit f5478e4

Browse files
committed
[docs update]完善限流的介绍
1 parent 294fe56 commit f5478e4

File tree

1 file changed

+41
-2
lines changed

1 file changed

+41
-2
lines changed

docs/high-availability/limit-request.md

+41-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ category: 高可用
2525
- 1 分钟之内每处理一个请求之后就将 `counter+1` ,当 `counter=33` 之后(也就是说在这 1 分钟内接口已经被访问 33 次的话),后续的请求就会被全部拒绝。
2626
- 等到 1 分钟结束后,将 `counter` 重置 0,重新开始计数。
2727

28-
**这种限流算法无法保证限流速率,因而无法保证突然激增的流量。**
28+
这种限流算法限流不够平滑。例如,我们限制某个接口每分钟只能访问 30 次,假设前 30 秒就有 30 个请求到达的话,那后续 30 秒将无法处理请求,这是不可取的,用户体验极差!
2929

30-
就比如说我们限制某个接口 1 分钟只能访问 1000 次,该接口的 QPS 为 500,前 55s 这个接口 1 个请求没有接收,后 1s 突然接收了 1000 个请求。然后,在当前场景下,这 1000 个请求在 1s 内是没办法被处理的,系统直接就被瞬时的大量请求给击垮了。
30+
除此之外,这种限流算法无法保证限流速率,因而无法应对突然激增的流量。例如,我们限制某个接口 1 分钟只能访问 1000 次,该接口的 QPS 为 500,前 55s 这个接口 1 个请求没有接收,后 1s 突然接收了 1000 个请求。然后,在当前场景下,这 1000 个请求在 1s 内是没办法被处理的,系统直接就被瞬时的大量请求给击垮了。
3131

3232
![固定窗口计数器算法](https://static001.infoq.cn/resource/image/8d/15/8ded7a2b90e1482093f92fff555b3615.png)
3333

@@ -43,6 +43,8 @@ category: 高可用
4343

4444
![滑动窗口计数器算法](https://static001.infoq.cn/resource/image/ae/15/ae4d3cd14efb8dc7046d691c90264715.png)
4545

46+
滑动窗口计数器算法可以应对突然激增的流量,但依然存在限流不够平滑的问题。
47+
4648
### 漏桶算法
4749

4850
我们可以把发请求的动作比作成注水到桶中,我们处理请求的过程可以比喻为漏桶漏水。我们往桶中以任意速率流入水,以一定速率流出水。当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。
@@ -51,12 +53,20 @@ category: 高可用
5153

5254
![漏桶算法](https://static001.infoq.cn/resource/image/75/03/75938d1010138ce66e38c6ed0392f103.png)
5355

56+
漏桶算法可以控制限流速率,避免网络拥塞和系统过载。不过,漏桶算法无法应对突然激增的流量,因为只能以固定的速率处理请求,对系统资源利用不够友好。
57+
58+
实际业务场景中,基本不会使用漏桶算法。
59+
5460
### 令牌桶算法
5561

5662
令牌桶算法也比较简单。和漏桶算法算法一样,我们的主角还是桶(这限流算法和桶过不去啊)。不过现在桶里装的是令牌了,请求在被处理之前需要拿到一个令牌,请求处理完毕之后将这个令牌丢弃(删除)。我们根据限流大小,按照一定的速率往桶里添加令牌。如果桶装满了,就不能继续往里面继续添加令牌了。
5763

5864
![令牌桶算法](https://static001.infoq.cn/resource/image/ec/93/eca0e5eaa35dac938c673fecf2ec9a93.png)
5965

66+
67+
68+
令牌桶算法可以限制平均速率和应对突然激增的流量,还可以动态调整生成令牌的速率。不过,如果令牌产生速率和桶的容量设置不合理,可能会出现问题比如大量的请求被丢弃、系统过载。
69+
6070
## 单机限流怎么做?
6171

6272
单机限流针对的是单体架构应用。
@@ -204,10 +214,39 @@ Resilience4j 不仅提供限流,还提供了熔断、负载保护、自动重
204214
205215
![ShenYu 限流脚本](https://oss.javaguide.cn/github/javaguide/csdn/e1e2a75f489e4854990dabe3b6cec522.jpg)
206216

217+
另外,如果不想自己写 Lua 脚本的话,也可以直接利用 Redisson 中的 `RRateLimiter` 来实现分布式限流,其底层实现就是基于 Lua 代码。
218+
219+
Redisson 是一个开源的 Java 语言 Redis 客户端,提供了很多开箱即用的功能,比如 Java 中常用的数据结构实现、分布式锁、延迟队列等等。并且,Redisson 还支持 Redis 单机、Redis Sentinel、Redis Cluster 等多种部署架构。
220+
221+
`RRateLimiter` 的使用方式非常简单。我们首先需要获取一个`RRateLimiter`对象,直接通过 Redisson 客户端获取即可。然后,设置限流规则就好。
222+
223+
```java
224+
// 创建一个 Redisson 客户端实例
225+
RedissonClient redissonClient = Redisson.create();
226+
// 获取一个名为 "javaguide.limiter" 的限流器对象
227+
RRateLimiter rateLimiter = redissonClient.getRateLimiter("javaguide.limiter");
228+
// 尝试设置限流器的速率为每小时 100 次
229+
// RateType 有两种,OVERALL是全局限流,ER_CLIENT是单Client限流(可以认为就是单机限流)
230+
rateLimiter.trySetRate(RateType.OVERALL, 100, 1, RateIntervalUnit.HOURS);
231+
```
232+
233+
接下来我们调用`acquire()`方法或`tryAcquire()`方法即可获取许可。
234+
235+
```java
236+
// 获取一个许可,如果超过限流器的速率则会等待
237+
// acquire()是同步方法,对应的异步方法:acquireAsync()
238+
rateLimiter.acquire(1);
239+
// 尝试在 5 秒内获取一个许可,如果成功则返回 true,否则返回 false
240+
// tryAcquire()是同步方法,对应的异步方法:tryAcquireAsync()
241+
boolean res = rateLimiter.tryAcquire(1, 5, TimeUnit.SECONDS);
242+
```
243+
207244
## 相关阅读
208245

209246
- 服务治理之轻量级熔断框架 Resilience4j:<https://xie.infoq.cn/article/14786e571c1a4143ad1ef8f19>
210247
- 超详细的 Guava RateLimiter 限流原理解析:<https://cloud.tencent.com/developer/article/1408819>
211248
- 实战 Spring Cloud Gateway 之限流篇 👍:<https://www.aneasystone.com/archives/2020/08/spring-cloud-gateway-current-limiting.html>
249+
- 详解 Redisson 分布式限流的实现原理:<https://juejin.cn/post/7199882882138898489>
250+
- 一文详解 Java 限流接口实现 - 阿里云开发者:<https://mp.weixin.qq.com/s/A5VYjstIDeVvizNK2HkrTQ>
212251

213252
<!-- @include: @article-footer.snippet.md -->

0 commit comments

Comments
 (0)