Java RateLimiter的限流詳解
限流背景
在早期的計算機領域,限流技術(time limiting)被用做控制網(wǎng)絡接口收發(fā)通信數(shù)據(jù)的速率。可以用來優(yōu)化性能,減少延遲和提高帶寬等?,F(xiàn)在在互聯(lián)網(wǎng)領域,也借鑒了這個概念,用來為服務控制請求的速率,如雙十一的限流,12306的搶票等。即使在細粒度的軟件架構中,也有類似的概念。
系統(tǒng)在使用下游資源時,需要考慮下游對資源受限,處理能力,在下游資源無法或者短時間內(nèi)無法提升處理性能的情況下,可以使用限流器或者類似保護機制,避免下游服務崩潰造成整體服務的不可用。
限流相關概念
在介紹限流之前先介紹幾個容易混淆的概念,包括服務熔斷,服務降級,服務隔離。
服務熔斷
理解熔斷之前先了解另一個概念:微服務的雪崩效應。因為熔斷機制通常是作為應對雪崩效應的一種微服務鏈路保護機制。
在微服務架構中,一個微服務通常是完成一個單一業(yè)務功能的獨立應用。這樣做的好處是各個業(yè)務功能之間最大可能的解耦,每個微服務可以獨立演進。通常一個應用可能會有很多個微服務組成,服務間通過RPC互相調(diào)用。假如有如下服務調(diào)用鏈路:
A,B依賴C去調(diào)用E,F(xiàn)。如果E服務不能正常提供服務了,C的超時重試機制將會執(zhí)行。同時新的調(diào)用不斷產(chǎn)生,會導致C對E服務的調(diào)用大量的積壓,產(chǎn)生大量的調(diào)用等待和重試調(diào)用,慢慢會耗盡C的資源,比如內(nèi)存或CPU,同時影響C調(diào)F,最終整個應用不可用。本例中由于鏈路上E的故障,對微服務A,B的調(diào)用就會占用越來越多的系統(tǒng)資源,進而引起系統(tǒng)崩潰,即所謂的“雪崩效應”。
熔斷機制是應對雪崩效應的一種微服務鏈路保護機制,生活中有很多熔斷的例子。比如電路中某個地方的電壓過高,熔斷器就會熔斷,對電路進行過載保護。股市里邊,如果股票指數(shù)漲跌幅過高,觸及設置的熔斷點后,隨后的一段時間內(nèi)將暫停交易。在微服務架構中的熔斷機制作用類似。當調(diào)用鏈路的某個微服務不可用,或者響應時間太長,或者錯誤次數(shù)達到某個閾值,會進行服務熔斷,即快速返回響應信息。當檢測到該節(jié)點微服務調(diào)用響應正常后,逐步恢復正常的調(diào)用鏈路。
服務降級
服務降級主要是指在服務器壓力陡增的情況下,根據(jù)某種策略對一些非核心服務或者頁面不做請求處理或者簡單處理,或者限流某個服務,從而釋放服務器資源以保證核心業(yè)務正常運作或高效運作。比如京東618活動時,把無關交易的服務降級,比如關閉某個服務,或者查看歷史訂單,商品歷史評論等非交易核心業(yè)務,只顯示最近100條等。
服務隔離
隔離是指服務或者資源隔離開。服務隔離能夠在服務發(fā)生故障時限定其影響范圍,保證其他服務還是可用的。資源隔離一般是指通過隔離來減少服務間資源競爭。資源隔離的粒度有很多種,比如線程隔離,進程隔離,機房隔離等。線程隔離即隔離線程池資源,不同服務的執(zhí)行使用不同的線程池。這樣做的好處是即使其中一個服務線程池滿了,也不會影響到其他的服務。比如下圖中Tomcat處理請求,對每個微服務,都分配一個線程池。
服務限流
服務限流是限制請求的數(shù)量,即某個時間窗口內(nèi)的請求速率。一旦達到限制速率則可以拒絕服務(定向到錯誤頁或告知系統(tǒng)忙),排隊等待(比如秒殺,用戶評論,下單),降級(返回兜底數(shù)據(jù)或默認數(shù)據(jù))。
比較
服務熔斷,服務降級都是從系統(tǒng)的可用性角度考慮,防止系統(tǒng)響應延遲甚至崩潰而采用的技術性的系統(tǒng)保護手段。服務熔斷一般是由某個下游服務故障引起,而服務降級一般是從整體業(yè)務的負載情況考慮,目的是為了降低系統(tǒng)負載。限流則是對單位時間內(nèi)請求次數(shù)的限制。三者都是通過某種手段保證流量過載時系統(tǒng)的可用性。服務隔離則是讓不同的業(yè)務使用各自獨立的線程池資源,避免服務之間資源競爭的影響。
常見的限流方法
常見的限流手段有如下這些。限制總的并發(fā)數(shù)(比如數(shù)據(jù)庫連接池,線程池),限制瞬時并發(fā)數(shù)(如nginx的limit_conn模塊,用來限制瞬時并發(fā)連接數(shù)),限制某個時間窗口內(nèi)的平均速率(RateLimiter,nginx的limit_req模塊);此外還有限制RPC調(diào)用頻率,限制MQ的消費速率等。
限流工具類RateLimiter
google開源工具包guava提供了限流工具類RateLimiter,該類基于“令牌桶算法”,非常方便使用。
RateLimiter 使用Demo:
import com.google.common.util.concurrent.RateLimiter; public class RateLimiterDemo { public static void main(String[] args) { // testNoRateLimiter(); testWithRateLimiter(); } public static void testNoRateLimiter() { Long start = System.currentTimeMillis(); for (int i = 0; i < 10; i++) { System.out.println("call execute.." + i); } Long end = System.currentTimeMillis(); System.out.println(end - start); } public static void testWithRateLimiter() { Long start = System.currentTimeMillis(); RateLimiter limiter = RateLimiter.create(10.0); // 每秒不超過10個任務被提交 for (int i = 0; i < 20; i++) { limiter.acquire(); // 請求RateLimiter, 超過permits會被阻塞 System.out.println("call execute.." + i); } Long end = System.currentTimeMillis(); System.out.println(end - start); } }
Guava版本
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>18.0</version> </dependency>
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內(nèi)容!
相關文章
關于Object中equals方法和hashCode方法判斷的分析
今天小編就為大家分享一篇關于關于Object中equals方法和hashCode方法判斷的分析,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01java中break和continue區(qū)別及使用場合分析
本文力圖通過實例加使用場合詳解來引導菜鳥重新認識break和continue語句,需要的朋友可以參考下2014-01-01