简介
Rate Limiter 是 Resilience4j 提供的一个重要组件,用于限制对资源(如API接口)的访问速率,以确保系统的高可用性和可靠性。Rate Limiter 通过控制单位时间内允许通过的请求数量来防止系统过载。本文将详细介绍如何在Java中使用Resilience4j的Rate Limiter。
内部机制
Resilience4j的Rate Limiter将自纪元开始以来的所有纳秒分成周期,每个周期的持续时间由RateLimiterConfig.limitRefreshPeriod
配置。在每个周期开始时,Rate Limiter会设置该周期内允许的活跃权限数(RateLimiterConfig.limitForPeriod
)。
Resilience4j提供了两种Rate Limiter实现:
- AtomicRateLimiter:通过
AtomicReference
管理状态,其内部状态(State
)是完全不可变的,包含activePermissions
(最后一次调用后剩余的可用权限数,如果某些权限被预留,则可能为负数)。 - SemaphoreBasedRateLimiter:使用Semaphores和调度器,在每个
limitRefreshPeriod
后刷新权限。
创建和配置RateLimiter
创建RateLimiterRegistry
类似于CircuitBreaker模块,RateLimiter模块也提供了一个内存中的RateLimiterRegistry
,用于管理(创建和检索)RateLimiter实例。
RateLimiterRegistry rateLimiterRegistry = RateLimiterRegistry.ofDefaults();
自定义全局RateLimiterConfig
你可以通过RateLimiterConfig
构建器来创建自定义的全局配置。
RateLimiterConfig config = RateLimiterConfig.custom()
.limitRefreshPeriod(Duration.ofMillis(1)) // 刷新周期
.limitForPeriod(10) // 每周期允许的最大请求数
.timeoutDuration(Duration.ofMillis(25)) // 请求超时时间
.build();
// 使用自定义配置创建Registry
RateLimiterRegistry registryWithCustomConfig = RateLimiterRegistry.of(config);
创建RateLimiter实例
通过Registry可以创建和检索RateLimiter实例。
RateLimiter rateLimiterWithDefaultConfig = registryWithCustomConfig.rateLimiter("name1"); // 使用默认配置
RateLimiter rateLimiterWithCustomConfig = registryWithCustomConfig.rateLimiter("name2", config); // 使用自定义配置
使用RateLimiter
装饰并执行功能接口
你可以使用RateLimiter来装饰任何可调用的方法或操作,限制其调用频率。
// 假设有一个BackendService类,其中有一个doSomething方法
BackendService backendService = new BackendService();
// 使用RateLimiter装饰doSomething方法
CheckedRunnable restrictedCall = RateLimiter.decorateCheckedRunnable(rateLimiterWithCustomConfig, backendService::doSomething);
// 执行操作,并处理异常情况
Try.run(restrictedCall)
.andThenTry(restrictedCall)
.onFailure(RequestNotPermitted.class, throwable -> LOG.info("Wait before calling it again :)"));
修改RateLimiter参数
在运行时,你可以修改RateLimiter的某些参数,如超时时间和每周期的请求限制数。
rateLimiterWithCustomConfig.changeTimeoutDuration(Duration.ofMillis(50)); // 修改超时时间
rateLimiterWithCustomConfig.changeLimitForPeriod(20); // 修改每周期的限制数
请注意,新的超时时间不会影响当前正在等待权限的线程,新的每周期限制数将从下一个周期开始应用。
监听事件
RegistryEvents
你可以注册事件监听器来响应RateLimiterRegistry中的事件(如RateLimiter的添加、替换或删除)。
registryWithCustomConfig.getEventPublisher()
.onEntryAdded(entryAddedEvent -> LOG.info("RateLimiter {} added", entryAddedEvent.getAddedEntry().getName()))
.onEntryRemoved(entryRemovedEvent -> LOG.info("RateLimiter {} removed", entryRemovedEvent.getRemovedEntry().getName()));
RateLimiterEvents
RateLimiter会发出包含成功获取权限或获取失败信息的事件流。你可以注册为事件消费者来消费这些事件。
// 使用RxJava或其他响应式编程库来转换EventPublisher为Reactive Stream
Spring 项目集成 ratelimiter 实战
注册
@SpringBootApplication
public class demoApplication {
// 其他代码...
@Bean("secondLismiter")
public RateLimiter perSecondLimiter() {
return RateLimiterRegistry.ofDefaults().rateLimiter("second-limiter",
RateLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(5))
.limitForPeriod(15) // 每秒 15 次
.limitRefreshPeriod(Duration.ofSeconds(1))
.build());
}
@Bean("minuteLimiter")
public RateLimiter perMinuteLimiter() {
return RateLimiterRegistry.ofDefaults().rateLimiter("minute-limiter",
RateLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(5))
.limitForPeriod(5000) // 每分 5000 次数
.limitRefreshPeriod(Duration.ofMinutes(1))
.build());
}
// 其他代码...
}
使用
@Resource(name = "SecondLimiter")
private RateLimiter secondLimiter;
@Resource(name = "minuteLimiter")
private RateLimiter minuteLimiter;
public DemoController() {
@RequestMapping("/demo/test")
@ResponseBody
public void test() {
// 其他代码...
// 分、秒限流器剩余可用次数
LOG.info("分限流器可用次数:" + secondLimiter.getMetrics().getAvailablePermissions());
LOG.info("秒限流器可用次数:" + minuteLimiter.getMetrics().getAvailablePermissions());
// 限流器校验请求
if (secondLimiter.acquirePermission() && minuteLimiter.acquirePermission(toList.length)) {
// 执行通过请求
// DEMO
} else {
// 打印限流请求
// LOG.warn("")
}
// 其他代码...
}
}
总结
Resilience4j的RateLimiter是一个功能强大的工具,用于限制对系统资源的访问速率,从而保护系统免受过载和拒绝服务攻击。通过自定义配置和灵活的API,你可以轻松地将其集成到你的Java应用程序中,并确保服务的高可用性和可靠性。