618年中購物節來了,高並發應用限流算法準備好了

618年中購物節來了,考驗系統的時候來了。在一個高併發系統中對流量的把控是非常重要的,當巨大的流量直接請求到我們的服務器上沒多久就可能造成接口不可用,不處理的話甚至會造成整個應用不可用。限流是解決高併發大流量的一種方案,至少是可以保證應用的可用性。不管使用何種算法,本質都是降低流量保證應用的高可用。

常見的漏桶算法非常簡單,就是將流量放入桶中並按照一定的速率流出。如果流量過大時候並不會提高流出效率,而溢出的流量也只能是拋棄掉了。這種算法很簡單,但也非常粗暴,無法應對突發的大流量。

618年中購物節來了,高併發應用限流算法準備好了

重點考慮令牌桶算法:

令牌桶算法是按照恆定的速率向桶中放入令牌,每當請求經過時則消耗一個或多個令牌。當桶中的令牌為 0 時,請求則會被阻塞。

令牌桶算法支持先消費後付款,比如一個請求可以獲取多個甚至全部的令牌,但是需要後面的請求付費。也就是說後面的請求需要等到桶中的令牌補齊之後才能繼續獲取。

通過RateLimiter實現:對於令牌桶的代碼實現,可以直接使用Guava包中的RateLimiter。

示例代碼:

public BaseResponse getUserByFeignBatch(@RequestBody UserReqVO userReqVO) {

//調用遠程服務

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 orderNo = orderServiceClient.getOrderNo(vo);

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 來完成。對於消峰,秒殺等場景,還要結合消息隊列,緩存共同協作處理,具體場景具體分析,歡迎留言區討論學習。

更多內容請關注每日編程,每天進步一點。


分享到:


相關文章: