面對(duì)突發(fā)流量,保證服務(wù)可用的4個(gè)手段
前言
不知道你有沒有這樣的經(jīng)歷,線上的系統(tǒng)突然來了很大的流量,有可能是黑客的攻擊,也有可能是業(yè)務(wù)量遠(yuǎn)遠(yuǎn)大于你的預(yù)估,如果你的系統(tǒng)沒有做任何的防護(hù)措施,這時(shí)候系統(tǒng)負(fù)載過高,系統(tǒng)資源慢慢耗盡,接口響應(yīng)越來越慢,直至不可用,這又導(dǎo)致了調(diào)用你接口的上游系統(tǒng)發(fā)生資源耗盡的情況,最終導(dǎo)致系統(tǒng)雪崩。想想就知道,這是一個(gè)災(zāi)難性的后果,那么有什么方法呢?
面對(duì)這種突發(fā)流量的場(chǎng)景,核心思路就是要優(yōu)先保證優(yōu)核心業(yè)務(wù)和優(yōu)先保證絕大部分用戶。常見的應(yīng)對(duì)手段有四種,降級(jí)、熔斷、限流和排隊(duì),下面我會(huì)一一講解。
1. 降級(jí)
降級(jí)指系統(tǒng)將某些業(yè)務(wù)或者接口的功能降低,可以是只提供部分功能,也可以是完全停掉所有功能,優(yōu)先保證核心功能。
比如淘寶雙11零點(diǎn)搶購(gòu)的時(shí)候你會(huì)發(fā)現(xiàn)商品的退貨功能不可以使用了。又比如論壇可以降級(jí)為只能看帖子,不能發(fā)帖子;也可以降級(jí)為只能看帖子和評(píng)論,不能發(fā)評(píng)論;
常見的實(shí)現(xiàn)降級(jí)的方式有兩種:
- 系統(tǒng)后門降級(jí)
簡(jiǎn)單來說,就是系統(tǒng)預(yù)留了后門用于降級(jí)操作。例如,系統(tǒng)提供一個(gè)降級(jí)URL,當(dāng)訪問這個(gè)URL時(shí),就相當(dāng)于執(zhí)行降級(jí)指令,具體的降級(jí)指令通過URL的參數(shù)傳入即可。這種方案有一定的安全隱患,所以也會(huì)在URL中加入密碼這類安全措施。
系統(tǒng)后門降級(jí)的方式實(shí)現(xiàn)成本低,但主要缺點(diǎn)是如果服務(wù)器數(shù)量多,需要一臺(tái)一臺(tái)去操作,效率比較低,這在故障處理爭(zhēng)分奪秒的場(chǎng)景下是比較浪費(fèi)時(shí)間的。
- 獨(dú)立降級(jí)系統(tǒng)
為了解決系統(tǒng)后門降級(jí)方式的缺點(diǎn),我們可以將降級(jí)操作獨(dú)立到一個(gè)單獨(dú)的系統(tǒng)中,實(shí)現(xiàn)復(fù)雜的權(quán)限管理、批量操作等功能。
基本架構(gòu)如下:
2. 熔斷
熔斷是指按照一定的規(guī)則,比如1分鐘內(nèi)60%的請(qǐng)求響應(yīng)錯(cuò)誤就停掉對(duì)外部接口的訪問,防止某些外部接口故障導(dǎo)致自己的系統(tǒng)處理能力急劇下降或者出故障。
熔斷和降級(jí)是兩個(gè)比較容易混淆的概念,因?yàn)閱渭儚拿稚峡?,好像都有禁止某個(gè)功能的意思。但它們的內(nèi)涵是不同的,因?yàn)榻导?jí)的目的是應(yīng)對(duì)系統(tǒng)自身的故障,而熔斷的目的是應(yīng)對(duì)依賴的外部系統(tǒng)故障的情況。
關(guān)于服務(wù)熔斷的實(shí)現(xiàn),比較主流的有兩種方案,??Spring Cloud Netflix Hystrix?
?和阿里的??Sentinel?
?,我們公司的項(xiàng)目用的是??Sentinel?
?。
- Hystrix是一個(gè)用于處理分布式系統(tǒng)的延遲和容錯(cuò)的一個(gè)開源庫(kù),在分布式系統(tǒng)里,許多依賴不可避免的會(huì)調(diào)用失敗,比如超時(shí)、異常等,Hystrix能保證在一個(gè)依賴出現(xiàn)問題的情況下,不會(huì)導(dǎo)致整體服務(wù)失敗,避免級(jí)聯(lián)故障,以提高分布式系統(tǒng)的穩(wěn)定性。
- Sentinel 是阿里中間件團(tuán)隊(duì)開源的,面向分布式服務(wù)架構(gòu)的輕量級(jí)高可用流量控制組件,主要以流量為切入點(diǎn),從流量控制、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)等多個(gè)維度來幫助用戶保護(hù)服務(wù)的穩(wěn)定性。
3. 限流
每個(gè)系統(tǒng)都有服務(wù)的上線,所以當(dāng)流量超過服務(wù)極限能力時(shí),系統(tǒng)可能會(huì)出現(xiàn)卡死、崩潰的情況,所以就有了降級(jí)和限流。限流其實(shí)就是:當(dāng)高并發(fā)或者瞬時(shí)高并發(fā)時(shí),為了保證系統(tǒng)的穩(wěn)定性、可用性,系統(tǒng)以犧牲部分請(qǐng)求為代價(jià)或者延遲處理請(qǐng)求為代價(jià),保證系統(tǒng)整體服務(wù)可用。
限流一般都是系統(tǒng)內(nèi)實(shí)現(xiàn)的,常見的限流方式可以分為兩類:基于請(qǐng)求限流和基于資源限流。
- 基于請(qǐng)求限流
基于請(qǐng)求限流指從外部訪問的請(qǐng)求角度考慮限流,常見的方式有兩種。
第一種是限制總量,也就是限制某個(gè)指標(biāo)的累積上限,常見的是限制當(dāng)前系統(tǒng)服務(wù)的用戶總量,例如:某個(gè)直播間限制總用戶數(shù)上限為100萬,超過100萬后新的用戶無法進(jìn)入;某個(gè)搶購(gòu)活動(dòng)商品數(shù)量只有100個(gè),限制參與搶購(gòu)的用戶上限為1萬個(gè),1萬以后的用戶直接拒絕。
第二種是限制時(shí)間量,也就是限制一段時(shí)間內(nèi)某個(gè)指標(biāo)的上限,例如1分鐘內(nèi)只允許10000個(gè)用戶訪問;每秒請(qǐng)求峰值最高為10萬。
無論是限制總量還是限制時(shí)間量,共同的特點(diǎn)都是實(shí)現(xiàn)簡(jiǎn)單,但在實(shí)踐中面臨的主要問題是比較難以找到合適的閾值。例如系統(tǒng)設(shè)定了1分鐘10000個(gè)用戶,但實(shí)際上6000個(gè)用戶的時(shí)候系統(tǒng)就扛不住了;或者達(dá)到1分鐘10000用戶后,其實(shí)系統(tǒng)壓力還不大,但此時(shí)已經(jīng)開始丟棄用戶訪問了。
即使找到了合適的閾值,基于請(qǐng)求限流還面臨硬件相關(guān)的問題。例如一臺(tái)32核的機(jī)器和64核的機(jī)器處理能力差別很大,閾值是不同的,可能有的技術(shù)人員以為簡(jiǎn)單根據(jù)硬件指標(biāo)進(jìn)行數(shù)學(xué)運(yùn)算就可以得出來,實(shí)際上這樣是不可行的,64核的機(jī)器比32核的機(jī)器,業(yè)務(wù)處理性能并不是2倍的關(guān)系,可能是1.5倍,甚至可能是1.1倍。
為了找到合理的閾值,通常情況下可以采用性能壓測(cè)來確定閾值,但性能壓測(cè)也存在覆蓋場(chǎng)景有限的問題,可能出現(xiàn)某個(gè)性能壓測(cè)沒有覆蓋的功能導(dǎo)致系統(tǒng)壓力很大;另外一種方式是逐步優(yōu)化:先設(shè)定一個(gè)閾值然后上線觀察運(yùn)行情況,發(fā)現(xiàn)不合理就調(diào)整閾值。
基于上述的分析,根據(jù)閾值來限制訪問量的方式更多的適應(yīng)于業(yè)務(wù)功能比較簡(jiǎn)單的系統(tǒng),例如負(fù)載均衡系統(tǒng)、網(wǎng)關(guān)系統(tǒng)、搶購(gòu)系統(tǒng)等。
- 基于資源限流
基于請(qǐng)求限流是從系統(tǒng)外部考慮的,而基于資源限流是從系統(tǒng)內(nèi)部考慮的,也就是找到系統(tǒng)內(nèi)部影響性能的關(guān)鍵資源,對(duì)其使用上限進(jìn)行限制。常見的內(nèi)部資源包括連接數(shù)、文件句柄、線程數(shù)和請(qǐng)求隊(duì)列等。
例如,采用Netty來實(shí)現(xiàn)服務(wù)器,每個(gè)進(jìn)來的請(qǐng)求都先放入一個(gè)隊(duì)列,業(yè)務(wù)線程再?gòu)年?duì)列讀取請(qǐng)求進(jìn)行處理,隊(duì)列長(zhǎng)度最大值為10000,隊(duì)列滿了就拒絕后面的請(qǐng)求;也可以根據(jù)CPU的負(fù)載或者占用率進(jìn)行限流,當(dāng)CPU的占用率超過80%的時(shí)候就開始拒絕新的請(qǐng)求。
基于資源限流相比基于請(qǐng)求限流能夠更加有效地反映當(dāng)前系統(tǒng)的壓力,但實(shí)際設(shè)計(jì)時(shí)也面臨兩個(gè)主要的難點(diǎn):如何確定關(guān)鍵資源,以及如何確定關(guān)鍵資源的閾值。
通常情況下,這也是一個(gè)逐步調(diào)優(yōu)的過程:設(shè)計(jì)的時(shí)候先根據(jù)推斷選擇某個(gè)關(guān)鍵資源和閾值,然后測(cè)試驗(yàn)證,再上線觀察,如果發(fā)現(xiàn)不合理,再進(jìn)行優(yōu)化。
4. 排隊(duì)
排隊(duì)這種方式,想必大家在熟悉不過了。大家在12306買火車票的時(shí)候,是不是會(huì)告訴你在排隊(duì)中,等待一段時(shí)間后才會(huì)鎖定車票,付款。年底時(shí),全中國(guó)那么多人買票,12306就是通過排隊(duì)機(jī)制來搞定的。但是也有缺點(diǎn),那就是用戶體驗(yàn)沒那么好。
由于排隊(duì)需要臨時(shí)緩存大量的業(yè)務(wù)請(qǐng)求,單個(gè)系統(tǒng)內(nèi)部無法緩存這么多數(shù)據(jù),一般情況下,排隊(duì)需要用獨(dú)立的系統(tǒng)去實(shí)現(xiàn),例如使用Kafka這類消息隊(duì)列來緩存用戶請(qǐng)求。
- 排隊(duì)模塊
負(fù)責(zé)接收用戶的搶購(gòu)請(qǐng)求,將請(qǐng)求以先入先出的方式保存下來。每一個(gè)參加秒殺活動(dòng)的商品保存一個(gè)隊(duì)列,隊(duì)列的大小可以根據(jù)參與秒殺的商品數(shù)量(或加點(diǎn)余量)自行定義。
- 調(diào)度模塊
負(fù)責(zé)排隊(duì)模塊到服務(wù)模塊的動(dòng)態(tài)調(diào)度,不斷檢查服務(wù)模塊,一旦處理能力有空閑,就從排隊(duì)隊(duì)列頭上把用戶訪問請(qǐng)求調(diào)入服務(wù)模塊,并負(fù)責(zé)向服務(wù)模塊分發(fā)請(qǐng)求。這里調(diào)度模塊扮演一個(gè)中介的角色,但不只是傳遞請(qǐng)求而已,它還擔(dān)負(fù)著調(diào)節(jié)系統(tǒng)處理能力的重任。我們可以根據(jù)服務(wù)模塊的實(shí)際處理能力,動(dòng)態(tài)調(diào)節(jié)向排隊(duì)系統(tǒng)拉取請(qǐng)求的速度。
- 服務(wù)模塊
負(fù)責(zé)調(diào)用真正業(yè)務(wù)來處理服務(wù),并返回處理結(jié)果,調(diào)用排隊(duì)模塊的接口回寫業(yè)務(wù)處理結(jié)果。
總結(jié)
最后我們通過一個(gè)表格在總結(jié)以下上面4種保證服務(wù)高可用的手段。
參考:??https://freegeektime.com/100006601/10312/?
?