- 接口級故障:系統(tǒng)沒有宕機(jī)档叔、網(wǎng)絡(luò)沒有中斷桌粉,但是業(yè)務(wù)卻出現(xiàn)了問題:業(yè)務(wù)響應(yīng)慢、大量訪問超時(shí)衙四、大量訪問異常铃肯。
- 本質(zhì):系統(tǒng)負(fù)載過高,導(dǎo)致無法快速處理業(yè)務(wù)传蹈。比如押逼,如果系統(tǒng)中存在慢查詢,當(dāng)負(fù)載過高時(shí)惦界,慢查詢會(huì)將數(shù)據(jù)庫資源耗盡挑格,導(dǎo)致讀寫操作超時(shí),業(yè)務(wù)讀寫很容易出現(xiàn)超時(shí)現(xiàn)象沾歪。即使沒有慢查詢當(dāng)負(fù)載過高時(shí)也會(huì)出現(xiàn)超時(shí)情況漂彤。
- 產(chǎn)生原因的內(nèi)部條件:程序bug導(dǎo)致死循環(huán)、存在慢查詢灾搏、程序邏輯不對導(dǎo)致耗盡內(nèi)存
- 外部條件:黑客攻擊显歧、促銷、第三方系統(tǒng)響應(yīng)緩慢
解決思路
- 解決接口級故障的核心思想是優(yōu)先保障核心業(yè)務(wù)和優(yōu)先保障絕大部分用戶确镊。比如登錄功能很重要士骤,當(dāng)訪問量過高時(shí),停掉注冊功能蕾域,為登錄騰出資源拷肌。
解決策略
降級
系統(tǒng)將某些不重要的業(yè)務(wù)或接口的功能降低,可以只提供部分功能旨巷,也可以完全停到所有所有不重要的功能巨缘。降級的思想是丟車保帥。
- 常見降級方式
- 系統(tǒng)后門降級:系統(tǒng)預(yù)留后門用于降級采呐,比如提供一個(gè)降級URL若锁,訪問URL時(shí)就執(zhí)行降級指令。缺點(diǎn):如果服務(wù)器數(shù)量多斧吐,需要一臺一臺去操作又固,效率低仲器。
-
獨(dú)立系統(tǒng)降級:將降級操作獨(dú)立到一個(gè)單獨(dú)的系統(tǒng)中,可以實(shí)現(xiàn)復(fù)雜的權(quán)限管理仰冠、批量操作等功能乏冀。
獨(dú)立降級系統(tǒng)
熔斷
降級是應(yīng)對系統(tǒng)自身的故障,而熔斷的目的是應(yīng)對外部系統(tǒng)的故障洋只。比如A服務(wù)的X功能依賴B服務(wù)的某個(gè)接口辆沦,當(dāng)B服務(wù)接口響應(yīng)很慢時(shí),A服務(wù)X功能的響應(yīng)也會(huì)被拖慢识虚,進(jìn)一步導(dǎo)致了A服務(wù)的線程都卡在了X功能上肢扯,A服務(wù)的其它功能也會(huì)卡主或拖慢。此時(shí)就需要熔斷機(jī)制担锤,即A服務(wù)不在請求B這個(gè)接口蔚晨,A服務(wù)內(nèi)部發(fā)現(xiàn)B接口就直接返回錯(cuò)誤,從而避免整個(gè)A服務(wù)被拖慢妻献。
- 實(shí)現(xiàn)思路:需要系統(tǒng)有一個(gè)統(tǒng)一的API調(diào)用層,由API來進(jìn)行采樣或者統(tǒng)計(jì)团赁。
限流
限流:只允許系統(tǒng)能夠承受的訪問量進(jìn)來育拨,超出的會(huì)被丟棄。
降級從系統(tǒng)功能優(yōu)先級角度考慮如何應(yīng)對故障欢摄,而限流則從用戶訪問壓力的角度來考慮如何應(yīng)對故障熬丧。
-
常見限流方式
-
基于請求限流:指從外部請求的角度考慮限流。常見的方式有:
- 限制總量:限制某個(gè)指標(biāo)的累積上限怀挠。比如直播間的用戶總數(shù)上限為100萬析蝴,超過后用戶無法進(jìn)入。搶購商品數(shù)量為100绿淋,限制搶購用戶上限為1萬個(gè)闷畸,超過或直接拒絕。
- 限制時(shí)間量:限制一段時(shí)間內(nèi)某個(gè)指標(biāo)的上限吞滞。例如:一分鐘內(nèi)只允許1000個(gè)用戶訪問佑菩。每秒請求峰值為10萬。
- 都需要找到合適的閥值:需要通過性能壓測來確定閥值或者逐步優(yōu)化裁赠。
基于資源限流:指從系統(tǒng)內(nèi)部考慮殿漠,找到影響性能的關(guān)鍵資源,對其使用上限限制佩捞。常見的內(nèi)部資源有:連接數(shù)绞幌、文件句柄、線程數(shù)一忱、請求隊(duì)列莲蜘、CPU利用率等谭确。例如,使用Netty實(shí)現(xiàn)服務(wù)器菇夸,每個(gè)請求先放到請求隊(duì)列中琼富,業(yè)務(wù)線程從請求隊(duì)列中獲取任務(wù)進(jìn)行處理,請求隊(duì)列大小為1000庄新,那么超過該值則直接拒絕鞠眉。
-
排隊(duì)
排隊(duì)方式來應(yīng)對接口級故障的方式是:讓用戶等待一段時(shí)間,而不是像限流方式直接拒絕用戶择诈。從體驗(yàn)上來講械蹋,雖然用戶沒有很快得到拒絕響應(yīng),但是如果等待時(shí)間過長羞芍,體驗(yàn)也不是很好哗戈。(但是對于一些請求,等待比直接拒絕要好荷科,比如支付請求唯咬,排隊(duì)總比直接拒絕好,因?yàn)橹苯泳芙^用戶就有可能不買了)
- 實(shí)現(xiàn)方式:排隊(duì)需要保存未被處理的請求畏浆,所以排隊(duì)需要緩存大量數(shù)據(jù)胆胰,一般單個(gè)系統(tǒng)無法緩存這么多數(shù)據(jù),所有需要單獨(dú)的排隊(duì)系統(tǒng)去實(shí)現(xiàn)刻获。例如使用Kafka蜀涨、RocketMQ等消息隊(duì)列來緩存用戶的請求。
實(shí)現(xiàn)思路:藍(lán)色區(qū)域是排隊(duì)系統(tǒng)
【排隊(duì)模塊】
負(fù)責(zé)將用戶的請求以FIFO的方式存入隊(duì)列中蝎毡,不同商品的秒殺請求放在不同的隊(duì)列中厚柳,隊(duì)列大小可以根據(jù)秒殺商品數(shù)量自行定義。
【調(diào)度模塊】
負(fù)責(zé)動(dòng)態(tài)調(diào)度排隊(duì)模塊中的請求到服務(wù)模塊中沐兵。動(dòng)態(tài)性體現(xiàn)在:會(huì)根據(jù)服務(wù)模塊的當(dāng)前處理能力控制拉取請求速度别垮,如果服務(wù)模塊的處理能力有空閑就提升拉取請求速度,否則降慢速度扎谎。
【服務(wù)模塊】
負(fù)責(zé)調(diào)用真正的業(yè)務(wù)來處理請求宰闰,并獲取返回結(jié)果,再調(diào)用排隊(duì)模塊的接口寫回業(yè)務(wù)處理結(jié)果簿透。
案例
如果你來設(shè)計(jì)一個(gè)整點(diǎn)限量秒殺系統(tǒng)移袍,包括登錄、搶購老充、支付(依賴支付寶)等核心功能葡盗,你會(huì)如何設(shè)計(jì)接口級的故障應(yīng)對手段?
- 思路:
丟車保帥:在秒殺時(shí),通過服務(wù)降級把注冊觅够、修改個(gè)人信息等非核心功能關(guān)閉掉胶背。(是否為核心此時(shí)的判斷標(biāo)準(zhǔn)為:秒殺時(shí)間段這些功能影響人數(shù)少)
熔斷:支付依賴第三方服務(wù),要設(shè)置熔斷策略喘先,熔斷后要給出友好提示钳吟,比如10分鐘后再來支付。
排隊(duì)+限流:搶購下單接口采用排隊(duì)+限流方式窘拯,如搶購1000件商品红且,則設(shè)置2000大小的隊(duì)列,請求超過2000后直接拒絕掉涤姊,前2000請求加入隊(duì)列中暇番,然后可以開啟多線程對隊(duì)列進(jìn)行處理。
內(nèi)容參考:《從0開始學(xué)架構(gòu)》
微服務(wù)接口限流的設(shè)計(jì)與思考(附GitHub框架源碼)