限流工具(令牌桶算法) RateLimiter使用 以及 注解@PostConstruct使用

本文介绍了如何使用Guava的RateLimiter实现服务的平均调用率限制,确保每秒不超过指定数量的请求。同时,通过@PostConstruct注解在Spring Bean初始化时配置RateLimiter,确保在依赖注入完成后正确设置限流参数,从而控制并发访问。此外,还讲解了RateLimiter的创建方法及其不同行为,包括平滑速率调整和热身期设置。最后,展示了如何使用tryAcquire()方法进行非阻塞限流,以实现降级运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 我们需要限制方法被调用的并发数不能超过100(同一时间并发数),则我们可以用信号量Semaphore实现。可如果我们要限制方法在一段时间内平均被调用次数不超过100,则需要使用RateLimiter。

@PostConstruct注解

  • 如果想在生成对象时完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么久无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。
  • 执行顺序为:Constructor >> @Autowired >> @PostConstruct
@Component
@Slf4j
public class RateLimitUtil {

    @Autowired
    private OSSConfigProperties ossConfigProperties;

    private RateLimiter limiter;
	
    @PostConstruct
    public void init() {
        if (limiter == null) {
        	// 控制每秒向令牌桶放多少个令牌
            limiter = RateLimiter.create(ossConfigProperties.getRate());
        }
    }

    public boolean tryAcquire() {
        return limiter.tryAcquire();
    }

}

RateLimiter主要接口

/**
* 创建一个稳定输出令牌的RateLimiter,保证了平均每秒不超过permitsPerSecond个请求
* 当请求到来的速度超过了permitsPerSecond,保证每秒只处理permitsPerSecond个请求
* 当这个RateLimiter使用不足(即请求到来速度小于permitsPerSecond),会囤积最多permitsPerSecond个请求
*/
public static RateLimiter create(double permitsPerSecond);

/**
 * 创建一个稳定输出令牌的RateLimiter,保证了平均每秒不超过permitsPerSecond个请求
 * 还包含一个热身期(warmup period),热身期内,RateLimiter会平滑的将其释放令牌的速率加大,直到起达到最大速率
 * 同样,如果RateLimiter在热身期没有足够的请求(unused),则起速率会逐渐降低到冷却状态
 * 
 * 设计这个的意图是为了满足那种资源提供方需要热身时间,而不是每次访问都能提供稳定速率的服务的情况(比如带缓存服务,需要定期刷新缓存的)
 * 参数warmupPeriod和unit决定了其从冷却状态到达最大速率的时间
*/
public static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit);

提供了两个获取令牌的方法,不带参数表示获取一个令牌.如果没有令牌则一直等待,返回等待的时间(单位为秒),没有被限流则直接返回0.0

public double acquire();

public double acquire(int permits);

尝试获取令牌,分为待超时时间和不带超时时间两种:

public boolean tryAcquire();
//尝试获取一个令牌,立即返回
public boolean tryAcquire(int permits);
public boolean tryAcquire(long timeout, TimeUnit unit);
//尝试获取permits个令牌,带超时时间
public boolean tryAcquire(int permits, long timeout, TimeUnit unit);

我们也可以使用非阻塞的形式达到降级运行的目的,即使用非阻塞的tryAcquire()方法:

if(limiter.tryAcquire()) { //未请求到limiter则立即返回false
    doSomething();
}else{
    doSomethingElse();
}

引用:https://blog.youkuaiyun.com/liyantianmin/article/details/79086571

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值