常見限流算法

常見的限流算法有:令牌桶、漏桶、計數器。

令牌桶

令牌桶算法:

  • 一個存放固定容量令牌的桶(假設容量爲n),
  • 按照固定速率往桶裏添加令牌(假設限速爲10r/s,則按照100毫秒的固定速率往桶中添加令牌,當桶滿時,新添加的令牌會被丟棄),
  • 請求過濾之後,需要先從桶裏獲取一個令牌,如果獲取到令牌,則進行業務處理;如果獲取不到則拒絕服務。

例子:Google開源項目Guava中的RateLimiter使用的就是令牌桶算法

漏桶

  • 一個固定容量的漏桶,按照固定速率流出水滴,如果桶是空的,則不需要流出水滴
  • 任意速率流入水滴到漏桶,如果流入水滴超出了桶的容量,則流入的水滴溢出(被丟棄)

例子:nginx的limit_req_zone 用來限制單位時間內的請求數,即速率限制,採用的漏桶算法 "leaky bucket"

令牌桶和漏桶算法比較:

  • 令牌桶是按照固定速率往桶中添加令牌,請求是否被處理需要看桶中令牌是否足夠,當令牌數量爲0時,則拒絕新的請求。
  • 漏桶則是按照常量固定速率流出請求,流入請求速率任意,當流入的請求數量累計到漏桶容量時,則新流入的請求被拒絕。
  • 令牌桶限制的是平均流入速率(允許突發請求,只要有令牌就可以處理,支持一次拿n個令牌),並允許一定程度的突發流量。
  • 漏桶限制的是常量流出速率(即流出速率是一個固定常量值,比如都是1的速率流出,而不能一次是1,下次是2),從而平滑突發流入速率。

計數器

        採用計數器實現限流有點簡單粗暴,一般我們會限制一秒鐘的能夠通過的請求數,比如限流qps爲100,算法的實現思路就是從第一個請求進來開始計時,在接下去的1s內,每來一個請求,就把計數加1,如果累加的數字達到了100,那麼後續的請求就會被全部拒絕。等到1s結束後,把計數恢復成0,重新開始計數。

        具體的實現可以是這樣的:對於每次服務調用,可以通過 AtomicLong#incrementAndGet()方法來給計數器加1並返回最新值,通過這個最新值和閾值進行比較。

        這種實現方式,相信大家都知道有一個弊端:如果我在單位時間1s內的前10ms,已經通過了100個請求,那後面的990ms,只能眼巴巴的把請求拒絕,我們把這種現象稱爲“突刺現象”。

應用場景:使用計數器來進行限流,主要用來限制總併發數,比如數據庫連接池大小、線程池大小、秒殺併發數,只要全局總請求數或者一定時間段的總請求數達到設定閥值,則進行限流。這是一種簡單粗暴的總數量限流,不是平均速率限流。

try{
    if(atomicLong.incrementAndGet() > 限流數){
        //拒絕請求
    }
    //處理請求
} finally {
   atomicLong.decrementAndGet();
}
		// 使用guava的Cache來存儲計數器
		LoadingCache<Long, AtomicLong> count = CacheBuilder.newBuilder()
				// 設置過期時間是2秒,保證在1秒之內該計數器是可用的
				.expireAfterWrite(2, TimeUnit.SECONDS)
				//
				.build(new CacheLoader<Long, AtomicLong>() {
					@Override
					public AtomicLong load(Long seconds) throws Exception {
						return new AtomicLong(0);
					}
				});
		// 設置限速
		long limit = 5L;
		// 進行5波請求,每波請求請求數是10
		for (int loop = 0; loop < 5; loop++) {
			Thread.sleep(1000L);
			for (int i = 0; i < 10; i++) {
				// 得到當前秒
				long currentSeconds = System.currentTimeMillis() / 1000;
				if (count.get(currentSeconds).incrementAndGet() > limit) {
					System.out.println(currentSeconds + "限流");
				} else {
					// 業務處理
					System.out.println(currentSeconds + "業務處理");
				}
			}
		}

運行結果

1593227195業務處理
1593227195業務處理
1593227195業務處理
1593227195業務處理
1593227195業務處理
1593227195限流
1593227195限流
1593227195限流
1593227195限流
1593227195限流
1593227196業務處理
1593227196業務處理
1593227196業務處理
1593227196業務處理
1593227196業務處理
1593227196限流
1593227196限流
1593227196限流
1593227196限流
1593227196限流
1593227197業務處理
1593227197業務處理
1593227197業務處理
1593227197業務處理
1593227197業務處理
1593227197限流
1593227197限流
1593227197限流
1593227197限流
1593227197限流
1593227198業務處理
1593227198業務處理
1593227198業務處理
1593227198業務處理
1593227198業務處理
1593227198限流
1593227198限流
1593227198限流
1593227198限流
1593227198限流
1593227199業務處理
1593227199業務處理
1593227199業務處理
1593227199業務處理
1593227199業務處理
1593227199限流
1593227199限流
1593227199限流
1593227199限流
1593227199限流

參考https://blog.csdn.net/weixin_41846320/article/details/95941361

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章