如何选型架构师必备的限流方案?
摘要:大家好,我是Java烘焙师。为了避免突增流量引起服务雪崩,需要对接口、存储资源做限流保护,根据系统负载情况设置合适的限流值。下面结合笔者的经验和思考,对主要限流方案的选型做一下总结,本篇先看如何使用,下一篇再看背后的原理。 下面介绍几种常见
大家好,我是Java烘焙师。为了避免突增流量引起服务雪崩,需要对接口、存储资源做限流保护,根据系统负载情况设置合适的限流值。下面结合笔者的经验和思考,对主要限流方案的选型做一下总结,本篇先看如何使用,下一篇再看背后的原理。
下面介绍几种常见限流方案的使用方法、优缺点:
单机限流:Guava RateLimiter
同时支持单机限流、集群限流:Sentinel
分布式限流:Redisson RateLimiter
1. 单机限流:Guava RateLimiter
使用
官网API文档:https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/util/concurrent/RateLimiter.html
Guava是Google开源的Java类库,提供了很多实用的工具,包括集合、本地缓存、并发编程工具等。Guava RateLimiter就是其中的单机限流工具,核心概念如下:
每秒允许通过的最大permits:
当请求获取1个permit时,就相当于是qps限流
当请求获取多个permits时,代表该请求需要消耗多少资源,比如想限定更新DB的SQL qps为1000,则需获取1000 permits
支持预热:在预热期内逐步支持到最大permits,适用于需要预热缓存资源的场景
允许突发流量:每次请求是否被限流,不取决于该次请求permits的多少,而是取决于前一次请求,前一次请求的permits越多,则后续请求需等待的时间越长
比如有一个空闲的RateLimiter,第一次请求无论是获取1 permit、还是10000 permits,都能立刻成功,但是会计算出下一次permits可用的时间。那么第一次请求是10000 permits时,第二次请求即使只需10 permits也可能要长时间等待
如下分别是阻塞、非阻塞方式,使用Guava RateLimiter的示例。
// 创建一个每秒允许10个permits的限流器
RateLimiter rateLimiter = RateLimiter.create(10.0);
// 1. 阻塞的方式
long startTime = System.currentTimeMillis();
// 获取5 permits;如果充足,则获取成功,否则阻塞等待
rateLimiter.aquire(5);
long endTime = System.currentTimeMillis();
// 打印阻塞等待的时间
System.out.println("Processing business logic. Waiting time ms: " + (endTime - startTime));
// 2. 非阻塞的方式
// 尝试获取1 permit
if (rateLimiter.tryAcquire()) {
// 如果能获取到令牌,则继续处理业务逻辑
System.out.println("Processing business logic...");
} else {
// 否则快速失败,返回友好提示或执行降级逻辑
System.out.println("Too many requests.");
}
优点
性能极高:纯计算,无网络开销
实现简单
缺点
无法跨实例协同,从整体层面控制限流
2. 同时支持单机限流、集群限流:Sentinel
使用
官网文档:https://sentinelguard.io/zh-cn/docs/introduction.html
Sentinel是阿里开源的流量治理组件,在国内使用较广泛。核心概念如下:
资源:可以是接口(调入、调出均可),也可以是任何一段代码逻辑。可通过sentinel注解、或者sentinel API包装成受保护的资源
规则:围绕资源的实时状态设定的规则,包括流量控制规则、熔断降级规则以及系统保护规则,所有规则都可以动态实时调整。
