springmvc限流拦截器,另有视频教学!

限流器算法

目前常用限流器算法为两种:令牌桶算法和漏桶算法,主要区别在于:漏桶算法能够强行限制请求速率,平滑突发请求,而令牌桶算法在限定平均速率的情况下,允许一定量的突发请求

下面是两张算法图示,就很容易区分这两种算法的特性了

漏桶算法

springmvc限流拦截器,另有视频教学!

令牌桶算法

springmvc限流拦截器,另有视频教学!

针对接口来说,一般会允许处理一定量突发请求,只要求限制平均速率,所以令牌桶算法更加常见。

令牌桶算法工具RateLimiter

目前本人常用的令牌桶算法实现类当属google guava的RateLimiter,guava不仅实现了令牌桶算法,还有缓存、新的集合类、并发工具类、字符串处理类等等。是一个强大的工具集

RateLimiter api可以查看并发编程网guava RateLimiter的介绍

RateLimiter源码分析

RateLimiter默认情况下,最核心的属性有两个nextFreeTicketMicros,下次可获取令牌时间,storedPermits桶内令牌数。

判断是否可获取令牌:

每次获取令牌的时候,根据桶内令牌数计算最快下次能获取令牌的时间nextFreeTicketMicros,判断是否可以获取资源时,只要比较nextFreeTicketMicros和当前时间就可以了,so easy

获取令牌操作:

对于获取令牌,根据nextFreeTicketMicros和当前时间计算出新增的令牌数,写入当前令牌桶令牌数,重新计算nextFreeTicketMicros,桶内还有令牌,则写入当前时间,并减少本次请求获取的令牌数。

如同java的AQS类一样,RateLimiter的核心在tryAcquire方法

public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {

//尝试获取资源最多等待时间

long timeoutMicros = max(unit.toMicros(timeout), 0);

//检查获取资源数目是否正确

checkPermits(permits);

long microsToWait;

//加锁

synchronized (mutex()) {

//当前时间

long nowMicros = stopwatch.readMicros();

//判断是否可以在timeout时间内获取资源

if (!canAcquire(nowMicros, timeoutMicros)) {

return false;

} else {

//可获取资源,对资源进行重新计算,并返回当前线程需要休眠时间

microsToWait = reserveAndGetWaitLength(permits, nowMicros);

}

}

//休眠

stopwatch.sleepMicrosUninterruptibly(microsToWait);

return true;

判断是否可获取令牌:

private boolean canAcquire(long nowMicros, long timeoutMicros) {

//最早可获取资源时间-等待时间<=当前时间 方可获取资源

return queryEarliestAvailable(nowMicros) - timeoutMicros <= nowMicros;

RateLimiter默认实现类的queryEarliestAvailable是取成员变量nextFreeTicketMicros

获取令牌并计算需要等待时间操作:

final long reserveAndGetWaitLength(int permits, long nowMicros) {

//获取下次可获取时间

long momentAvailable = reserveEarliestAvailable(permits, nowMicros);

//计算当前线程需要休眠时间

return max(momentAvailable - nowMicros, 0);

final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {

//重新计算桶内令牌数storedPermits

resync(nowMicros);

long returnValue = nextFreeTicketMicros;

//本次消耗的令牌数

double storedPermitsToSpend = min(requiredPermits, this.storedPermits);

//重新计算下次可获取时间nextFreeTicketMicros

double freshPermits = requiredPermits - storedPermitsToSpend;

long waitMicros =

storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)

+ (long) (freshPermits * stableIntervalMicros);

this.nextFreeTicketMicros = LongMath.saturatedAdd(nextFreeTicketMicros, waitMicros);

//减少桶内令牌数

this.storedPermits -= storedPermitsToSpend;

return returnValue;

实现简单的spring mvc限流拦截器

实现一个HandlerInterceptor,在构造方法中创建一个RateLimiter限流器

public SimpleRateLimitInterceptor(int rate) {

if (rate > 0)

globalRateLimiter = RateLimiter.create(rate);

else

throw new RuntimeException("rate must greater than zero");

在preHandle调用限流器的tryAcquire方法,判断是否已经超过限制速率

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

if (!globalRateLimiter.tryAcquire()) {

LoggerUtil.log(request.getRequestURI()+"请求超过限流器速率");

return false;

}

return true;

在dispatcher-servlet.xml中配置限流拦截器

<interceptors>

<interceptor>

<mapping>

<bean>

<constructor-arg>

复杂版本的spring mvc限流拦截器

使用Properties传入拦截的url表达式->速率rate

<interceptor>

<mapping>

<bean>

<property>

<props>

<prop>1/<prop>

<prop>2/<prop>

为每个url表达式创建一个对应的RateLimiter限流器。url表达式则封装为org.springframework.web.servlet.mvc.condition.PatternsRequestCondition。PatternsRequestCondition是springmvc 的DispatcherServlet中用来匹配请求和Controller的类,可以判断请求是否符合这些url表达式。

在拦截器preHandle方法中

//当前请求路径

String lookupPath = urlPathHelper.getLookupPathForRequest(request);

//迭代所有url表达式对应的PatternsRequestCondition

for (PatternsRequestCondition patternsRequestCondition : urlRateMap.keySet()) {

//进行匹配

List<string> matches = patternsRequestCondition.getMatchingPatterns(lookupPath);/<string>

if (!matches.isEmpty()) {

//匹配成功的则获取对应限流器的令牌

if (urlRateMap.get(patternsRequestCondition).tryAcquire()) {

LoggerUtil.log(lookupPath + " 请求匹配到" + Joiner.on(",").join(patternsRequestCondition.getPatterns()) + "限流器");

} else {

//获取令牌失败

LoggerUtil.log(lookupPath + " 请求超过" + Joiner.on(",").join(patternsRequestCondition.getPatterns()) + "限流器速率");

return false;

}

}

}

具体的实现类

为大家更好的理解高并发流量控制策略

为大家准备了视频讲解

springmvc限流拦截器,另有视频教学!

视频内容:

1.什么是高并发?

2.高并发带来的问题

3.高并发系统架构图

4.高并发的优化方案

5.为什么要限流

6.如何限流

7.限流算法

8.固定窗口

9.滑动窗口

10.漏桶算法

11.令牌桶算法

12.令牌桶算法限流实战

13.自定义注解和AOP

14.分布式场景下限流方案实战

15.高并发的优化方案和技术

16.互联网架构树

资料获取方式

关注+转发后,私信关键词 【架构】即可获取!

重要的事情说三遍,转发、转发、转发后再发私信,才可以拿到!


分享到:


相關文章: