天天看點

RateLimiter配合ConcurrentHashMap對使用者進行簡單限流

對于小不點的項目來說,RateLimiter配合ConcurrentHashMap可以對使用者進行簡單的限流,防止使用者頻繁刷量或者高頻請求。

RateLimiter 是 Guava 下的一個包,采用的是令牌桶算法:以一個恒定的速率向固定容量大小的桶中放入令牌,當有流量來的時候從桶中取出一個令牌。如果桶中沒有可用的令牌時就丢棄請求或者阻塞。

RateLimiter配合ConcurrentHashMap對使用者進行簡單限流

ConcurrentHashMap 是一個可以在并發環境下使用的 HashMap,通俗點說就是線程安全的。

大緻的思路也很簡單:當一個請求過來時,根據使用者的 ID 從 ConcurrentHashMap 取出 RateLimiter,然後嘗試取出令牌,如果擷取失敗,則提示使用者請求過于頻繁;否則進行業務處理。

首先在 Controller 類中建立一個 ConcurrentHashMap 對象。

private final static Map<Integer, RateLimiter> outMoneyLimitMap = new ConcurrentHashMap<>();

1

然後是請求的處理代碼。

public ModelAndView submitOut() {
    RateLimiter rateLimiter = null;
    if (outMoneyLimitMap.containsKey(uid)) {
        logger.debug("包含有該uid");
   
        rateLimiter = outMoneyLimitMap.get(uid);
    } else {
        logger.debug("沒有該uid");
        // 需要新增,一秒内 0.1 個令牌(10秒内一個令牌)
        rateLimiter = RateLimiter.create(0.1);
   
        outMoneyLimitMap.put(uid, rateLimiter);
    }
   
     if(!rateLimiter.tryAcquire()) {
        throw new OrderException("請求過于頻繁");
    }
    // 正常業務處理
}      

RateLimiter.create() 可以建立一個限流器,參數可以是 double,例子中為 0.1,即 10 秒内一個令牌(便于模拟)。

然後通過 rateLimiter.tryAcquire() 嘗試擷取令牌,如果擷取失敗,就提示使用者。否則正常業務處理。

整體思路非常非常簡單,實作起來也非常容易,是一種非常好用的限流示例。

繼續閱讀