618年中购物节来了,考验系统的时候来了。在一个高并发系统中对流量的把控是非常重要的,当巨大的流量直接请求到我们的服务器上没多久就可能造成接口不可用,不处理的话甚至会造成整个应用不可用。限流是解决高并发大流量的一种方案,至少是可以保证应用的可用性。不管使用何种算法,本质都是降低流量保证应用的高可用。
常见的漏桶算法非常简单,就是将流量放入桶中并按照一定的速率流出。如果流量过大时候并不会提高流出效率,而溢出的流量也只能是抛弃掉了。这种算法很简单,但也非常粗暴,无法应对突发的大流量。
重点考虑令牌桶算法:
令牌桶算法是按照恒定的速率向桶中放入令牌,每当请求经过时则消耗一个或多个令牌。当桶中的令牌为 0 时,请求则会被阻塞。
令牌桶算法支持先消费后付款,比如一个请求可以获取多个甚至全部的令牌,但是需要后面的请求付费。也就是说后面的请求需要等到桶中的令牌补齐之后才能继续获取。
通过RateLimiter实现:对于令牌桶的代码实现,可以直接使用Guava包中的RateLimiter。
示例代码:
public BaseResponse
//调用远程服务
OrderNoReqVO vo = new OrderNoReqVO() ;
vo.setReqNo(userReqVO.getReqNo());
RateLimiter limiter = RateLimiter.create(2.0) ;
//批量调用
for (int i = 0 ;i< 10 ; i++){
double acquire = limiter.acquire();
logger.debug("获取令牌成功!,消耗=" + acquire);
BaseResponse
logger.debug("远程返回:"+JSON.toJSONString(orderNo));
}
UserRes userRes = new UserRes() ;
userRes.setUserId(123);
userRes.setUserName("张三");
userRes.setReqNo(userReqVO.getReqNo());
userRes.setCode(StatusEnum.SUCCESS.getCode());
userRes.setMessage("成功");
return userRes ;
}
代码可以看出以每秒向桶中放入两个令牌,请求一次消耗一个令牌。所以每秒钟只能发送两个请求。
允许先消费,后付款,意思就是它可以来一个请求的时候一次性取走几个或者是剩下所有的令牌甚至多取,但是后面的请求就得为上一次请求买单,它需要等待桶中的令牌补齐之后才能继续获取令牌。
总结:
针对于单个应用的限流 RateLimiter 够用了,如果是分布式环境可以借助 Redis 来完成。对于消峰,秒杀等场景,还要结合消息队列,缓存共同协作处理,具体场景具体分析,欢迎留言区讨论学习。
更多内容请关注每日编程,每天进步一点。
閱讀更多 每日編程 的文章