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