resilience4j-ratelimiter 接口限速器

781 阅读3分钟

简介

Rate Limiter 是 Resilience4j 提供的一个重要组件,用于限制对资源(如API接口)的访问速率,以确保系统的高可用性和可靠性。Rate Limiter 通过控制单位时间内允许通过的请求数量来防止系统过载。本文将详细介绍如何在Java中使用Resilience4j的Rate Limiter。

内部机制

Resilience4j的Rate Limiter将自纪元开始以来的所有纳秒分成周期,每个周期的持续时间由RateLimiterConfig.limitRefreshPeriod配置。在每个周期开始时,Rate Limiter会设置该周期内允许的活跃权限数(RateLimiterConfig.limitForPeriod)。

Resilience4j提供了两种Rate Limiter实现:

  1. AtomicRateLimiter:通过AtomicReference管理状态,其内部状态(State)是完全不可变的,包含activePermissions(最后一次调用后剩余的可用权限数,如果某些权限被预留,则可能为负数)。
  2. 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应用程序中,并确保服务的高可用性和可靠性。

参考资料:github.com/resilience4…