国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

springmvc限流攔截器

2019-11-08 01:55:29
字體:
來源:轉載
供稿:網友

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中配置限流攔截器

<mvc:interceptors> <!--限流攔截器--> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="limit.SimpleRateLimitInterceptor"> <constructor-arg index="0" value="${totalRate}"/> </bean> </mvc:interceptor> </mvc:interceptors>

復雜版本的spring mvc限流攔截器

使用Properties傳入攔截的url表達式->速率rate

<mvc:interceptor> <mvc:mapping path="/**"/> <bean class="limit.RateLimitInterceptor"> <!--單url限流--> <property name="urlProperties"> <props> <prop key="/get/{id}">1</prop> <prop key="/post">2</prop> </props> </property> </bean></mvc:interceptor>

為每個url表達式創建一個對應的RateLimiter限流器。url表達式則封裝為org.springframework.web.servlet.mvc.condition.PatternsRequestCondition。PatternsRequestCondition是springmvc 的DispatcherServlet中用來匹配請求和Controller的類,可以判斷請求是否符合這些url表達式。 在攔截器preHandle方法中

//當前請求路徑String lookupPath = urlPathHelper.getLookupPathForRequest(request);//迭代所有url表達式對應的PatternsRequestConditionfor (PatternsRequestCondition patternsRequestCondition : urlRateMap.keySet()) { //進行匹配 List<String> matches = patternsRequestCondition.getMatchingPatterns(lookupPath); 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; } }}

具體的實現類

請見github


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 丹棱县| 南通市| 吉隆县| 呈贡县| 黎城县| 万安县| 浦东新区| 贡觉县| 丹棱县| 无为县| 天气| 兴山县| 安新县| 渝中区| 福泉市| 安泽县| 浙江省| 淮滨县| 搜索| 阿城市| 宜春市| 大石桥市| 台前县| 渭源县| 苗栗县| 黔西| 冀州市| 珲春市| 钟祥市| 江达县| 平远县| 泰和县| 行唐县| 山丹县| 安宁市| 林甸县| 额济纳旗| 洪雅县| 聂荣县| 祁连县| 依安县|