減少單點(diǎn)
去單點(diǎn)首先要識(shí)別整個(gè)系統(tǒng)所有主鏈路的單點(diǎn),如機(jī)房(同城異地雙機(jī)房)综苔,應(yīng)用服務(wù)器惩系,DNS服務(wù)器,SFTP服務(wù)器如筛,LBS堡牡,緩存服務(wù)器,數(shù)據(jù)庫杨刨,消息服務(wù)器晤柄,代理服務(wù)器和專線等崩溪,如系統(tǒng)通過專線調(diào)用對(duì)方服務(wù)吉捶,需要考慮同時(shí)拉聯(lián)通和電信的專線,聯(lián)通或電信的專線還是有一定概率會(huì)出現(xiàn)問題的龙优,但是同時(shí)出問題的概率會(huì)小非常多做粤。優(yōu)先使用軟負(fù)載浇借,使用硬負(fù)載兜底。
減少依賴
減少DNS依賴怕品,減少遠(yuǎn)程服務(wù)依賴妇垢,DNS依賴可以嘗試設(shè)置本地host,用工具給所有服務(wù)器推送最新的域名映射關(guān)系肉康,通過本地緩存或近端服務(wù)減少RPC調(diào)用闯估。
限制循環(huán)
避免無限死循環(huán),導(dǎo)致CPU利用率百分百吼和,可以設(shè)置for循環(huán)的最大循環(huán)次數(shù)涨薪,如最大循環(huán)1000次。
控制流量
避免異常流量對(duì)應(yīng)用服務(wù)器產(chǎn)生影響炫乓,可以對(duì)指定服務(wù)設(shè)置流量限制刚夺,如QPS献丑,TPS,QPH(每小時(shí)總請(qǐng)求量)和QPD(每天總請(qǐng)求量),可主要參考漏桶算法和令牌桶算法侠姑。
精準(zhǔn)監(jiān)控
對(duì)CPU利用率创橄,load,內(nèi)存莽红,帶寬妥畏,系統(tǒng)調(diào)用量,應(yīng)用錯(cuò)誤量安吁,PV醉蚁,UV和業(yè)務(wù)量進(jìn)行監(jiān)控,避免內(nèi)存泄露和異常代碼對(duì)系統(tǒng)產(chǎn)生影響鬼店,配置監(jiān)控一定要精準(zhǔn)馍管,如平時(shí)內(nèi)存利用率是50%,監(jiān)控可以配置成60%進(jìn)行報(bào)警薪韩,這樣可以提前感知內(nèi)存泄露問題确沸,避免應(yīng)用無響應(yīng)。
無狀態(tài)
服務(wù)器不能保存用戶狀態(tài)數(shù)據(jù)俘陷,如在集群環(huán)境下不能用static變量保存用戶數(shù)據(jù)罗捎,不能長時(shí)間把用戶文件存放在服務(wù)器本地。服務(wù)器有狀態(tài)會(huì)難以擴(kuò)容拉盾,且出現(xiàn)單點(diǎn)問題桨菜。
容量規(guī)劃
定期對(duì)容量進(jìn)行評(píng)估。如大促前進(jìn)行壓測和容量預(yù)估捉偏,根據(jù)需要進(jìn)行擴(kuò)容倒得。
服務(wù)補(bǔ)償
分布式架構(gòu)中第三方服務(wù)出現(xiàn)異常或網(wǎng)絡(luò)抖動(dòng)影響夭禽,記錄失敗請(qǐng)求霞掺,通過定時(shí)任務(wù)或延遲隊(duì)列按一定周期對(duì)失敗請(qǐng)求進(jìn)行重復(fù)冪等通知進(jìn)行補(bǔ)償,具體可參考支付寶支付完成通知實(shí)現(xiàn)方案讹躯。
冪等設(shè)計(jì)
為保證服務(wù)可重試菩彬,可補(bǔ)償,需要API盡量支持冪等潮梯,腳本支持可重復(fù)執(zhí)行骗灶,服務(wù)支持平滑重啟。
功能開關(guān)
打開和關(guān)閉某些功能秉馏,比如消息量過大耙旦,系統(tǒng)處理不了,把開關(guān)打開后直接丟棄消息不處理萝究。上線新功能增加開關(guān)免都,如果有問題關(guān)閉新功能锉罐,功能開關(guān)可通過配置中心實(shí)現(xiàn),可以參考開源項(xiàng)目confd或自己通過etcd,zk等實(shí)現(xiàn)琴昆。
設(shè)置超時(shí)
設(shè)置連接超時(shí)和讀超時(shí)設(shè)置氓鄙,不應(yīng)該太大馆揉,如果是內(nèi)部調(diào)用連接超時(shí)可以設(shè)置成1秒业舍,讀超時(shí)3秒,外部系統(tǒng)調(diào)用連接超時(shí)可以設(shè)置成3秒升酣,讀超時(shí)設(shè)置成20秒舷暮。
重試策略
當(dāng)調(diào)用外部服務(wù)異常時(shí)可以設(shè)置重試策略,每次重試時(shí)間遞增噩茄,但是需要設(shè)置最大重試次數(shù)和重試開關(guān)下面,避免對(duì)下游系統(tǒng)產(chǎn)生影響。
隔離
應(yīng)用隔離绩聘,模塊隔離沥割,機(jī)房隔離和線程池隔離≡淦校可以按照優(yōu)先級(jí)机杜,不變和變幾個(gè)維度來隔離應(yīng)用和模塊,如抽象和不變的代碼放在一個(gè)模塊衅谷,這個(gè)模塊的代碼幾乎不會(huì)修改椒拗,可用性高,經(jīng)常變的業(yè)務(wù)邏輯放在一個(gè)模塊里获黔,這樣就算有問題蚀苛,也只會(huì)影響到某一個(gè)業(yè)務(wù)。不同的業(yè)務(wù)使用不同的線程池玷氏,避免低優(yōu)先級(jí)任務(wù)阻塞高優(yōu)先級(jí)堵未,或高優(yōu)先級(jí)任務(wù)過多時(shí)影響低優(yōu)先級(jí)任務(wù)永遠(yuǎn)不會(huì)執(zhí)行。
異步調(diào)用
同步調(diào)用改成異步調(diào)用盏触,解決遠(yuǎn)程調(diào)用故障或調(diào)用超時(shí)對(duì)系統(tǒng)的影響兴溜。
熱點(diǎn)緩存
對(duì)熱點(diǎn)數(shù)據(jù)進(jìn)行緩存,降低RPC調(diào)用耻陕。如B系統(tǒng)提供名單服務(wù)拙徽,B系統(tǒng)可以提供一個(gè)client SDK提供近端緩存服務(wù),定期去服務(wù)器端取數(shù)據(jù)诗宣,減少RPC調(diào)用膘怕。
緩存容災(zāi)
當(dāng)數(shù)據(jù)庫不可用時(shí)可以使用緩存的數(shù)據(jù)。并設(shè)置分級(jí)緩存召庞,如優(yōu)先讀本地緩存岛心,其次讀分布式緩存来破。
多級(jí)緩存
優(yōu)先讀本地緩存,其次讀分布式緩存忘古。通過推模式更新本地緩存徘禁。
系統(tǒng)分級(jí)
對(duì)系統(tǒng)進(jìn)行分級(jí),如ABC三個(gè)等級(jí)髓堪,高級(jí)別系統(tǒng)不依賴于低級(jí)別系統(tǒng)送朱,并且高級(jí)別系統(tǒng)比底級(jí)別系統(tǒng)高可用率要高。
服務(wù)拆分
對(duì)業(yè)務(wù)按照功能模塊進(jìn)行服務(wù)拆分干旁,可有效提高服務(wù)的可擴(kuò)展性驶沼,可維護(hù)性,解除服務(wù)與服務(wù)之間的耦合争群。
服務(wù)降級(jí)
如果系統(tǒng)出現(xiàn)響應(yīng)緩慢等狀況回怜,可以關(guān)閉部分功能,從而釋放系統(tǒng)資源换薄,保證核心服務(wù)的正常運(yùn)行玉雾。需要識(shí)別哪些服務(wù)可以降級(jí),比如突然有大量消息流入轻要,導(dǎo)致服務(wù)不可用复旬,我們會(huì)把消息直接丟棄掉÷赘或通過設(shè)置流控赢底,拒絕為低級(jí)別系統(tǒng)提供服務(wù)。
流量蓄洪
當(dāng)流量陡增時(shí)柏蘑,可以將請(qǐng)求進(jìn)行蓄洪幸冻,如把請(qǐng)求保存在數(shù)據(jù)庫中,再按照指定的QPS進(jìn)行泄洪咳焚,有效的保護(hù)下游系統(tǒng)洽损,也保證了服務(wù)的可用性。當(dāng)調(diào)用對(duì)方系統(tǒng)革半,對(duì)方系統(tǒng)響應(yīng)緩慢或無響應(yīng)時(shí)碑定,可采取自動(dòng)蓄洪。
服務(wù)權(quán)重
在集群環(huán)境中又官,可自動(dòng)識(shí)別高性能服務(wù)延刘,拒絕調(diào)用性能低的服務(wù)。如在集群環(huán)境中六敬,對(duì)調(diào)用超時(shí)的服務(wù)器進(jìn)行權(quán)重降低碘赖,優(yōu)先調(diào)用權(quán)重高的服務(wù)器。
依賴簡化
減少系統(tǒng)之間的依賴,比如使用消息驅(qū)動(dòng)普泡,A和B系統(tǒng)通過消息服務(wù)器傳遞數(shù)據(jù)播掷,A和B系統(tǒng)使用數(shù)據(jù)庫進(jìn)行讀寫分離,A系統(tǒng)負(fù)責(zé)往數(shù)據(jù)庫中寫數(shù)據(jù)撼班,B系統(tǒng)負(fù)責(zé)讀數(shù)據(jù)歧匈,因?yàn)閿?shù)據(jù)存放在數(shù)據(jù)庫中,當(dāng)A不可用時(shí)砰嘁,短時(shí)間內(nèi)不影響B(tài)系統(tǒng)提供服務(wù)件炉。
彈性擴(kuò)容
根據(jù)資源的使用率自動(dòng)或手動(dòng)進(jìn)行擴(kuò)容。如帶寬不夠用時(shí)般码,快速增加帶寬妻率。
灰度和回滾
發(fā)布新功能只讓部分服務(wù)器生效乱顾,且觀察幾天逐漸切流板祝,如果出現(xiàn)問題只影響部分客戶。出現(xiàn)問題快速回滾走净,或者直接下線灰度的機(jī)器券时。
減少遠(yuǎn)程調(diào)用
優(yōu)先調(diào)用本地JVM內(nèi)服務(wù),其次是同機(jī)房服務(wù)伏伯,然后是同城服務(wù)橘洞,最后是跨城服務(wù)。如A調(diào)用B说搅,B調(diào)用互聯(lián)網(wǎng)的C系統(tǒng)獲取數(shù)據(jù)炸枣,B系統(tǒng)可以把數(shù)據(jù)緩存起來,并設(shè)置數(shù)據(jù)的保鮮度弄唧,減少B對(duì)C的依賴适肠。配置中心把注冊(cè)服務(wù)的地址推送到調(diào)用服務(wù)的系統(tǒng)本地。參數(shù)中心把參數(shù)配置信息推送到系統(tǒng)的本地內(nèi)存候引,而不是讓系統(tǒng)去遠(yuǎn)程服務(wù)器獲取參數(shù)信息侯养。
熔斷機(jī)制
增加熔斷機(jī)制,當(dāng)監(jiān)控出線上數(shù)據(jù)出現(xiàn)大幅跌漲時(shí)澄干,及時(shí)中斷逛揩,避免對(duì)業(yè)務(wù)產(chǎn)生更大影響。如我們做指標(biāo)計(jì)算時(shí)麸俘,指標(biāo)可以計(jì)算慢辩稽,但是不能算錯(cuò),如果發(fā)現(xiàn)某個(gè)用戶的指標(biāo)環(huán)比或同比增長一倍或跌零从媚,會(huì)考慮保存所有消息逞泄,并中止該用戶的指標(biāo)計(jì)算。
運(yùn)行時(shí)加載模塊
我們會(huì)把經(jīng)常變的業(yè)務(wù)代碼變成一個(gè)個(gè)業(yè)務(wù)模塊,使用Java的ClassLoader在運(yùn)行時(shí)動(dòng)態(tài)加載和卸載模塊炭懊,當(dāng)某個(gè)模塊有問題時(shí)候并级,可以快速修復(fù)。
代碼掃描
使用IDEA代碼分析等工具進(jìn)行代碼掃描侮腹,識(shí)別出程序中的BUG嘲碧,如空指針異常,循環(huán)依賴等父阻。
應(yīng)用舉例
- 接口級(jí)故障:系統(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)躁绸、存在慢查詢裕循、程序邏輯不對(duì)導(dǎo)致耗盡內(nèi)存
- 外部條件:黑客攻擊、促銷净刮、第三方系統(tǒng)響應(yīng)緩慢
解決思路
- 解決接口級(jí)故障的核心思想是優(yōu)先保障核心業(yè)務(wù)和優(yōu)先保障絕大部分用戶剥哑。比如登錄功能很重要,當(dāng)訪問量過高時(shí)庭瑰,停掉注冊(cè)功能星持,為登錄騰出資源。
解決策略
降級(jí)
系統(tǒng)將某些不重要的業(yè)務(wù)或接口的功能降低弹灭,可以只提供部分功能督暂,也可以完全停到所有所有不重要的功能。降級(jí)的思想是丟車保帥穷吮。
- 常見降級(jí)方式
系統(tǒng)后門降級(jí):系統(tǒng)預(yù)留后門用于降級(jí)逻翁,比如提供一個(gè)降級(jí)URL,訪問URL時(shí)就執(zhí)行降級(jí)指令捡鱼。缺點(diǎn):如果服務(wù)器數(shù)量多八回,需要一臺(tái)一臺(tái)去操作,效率低。
-
獨(dú)立系統(tǒng)降級(jí):將降級(jí)操作獨(dú)立到一個(gè)單獨(dú)的系統(tǒng)中缠诅,可以實(shí)現(xiàn)復(fù)雜的權(quán)限管理溶浴、批量操作等功能。
image
熔斷
降級(jí)是應(yīng)對(duì)系統(tǒng)自身的故障管引,而熔斷的目的是應(yīng)對(duì)外部系統(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ù)不在請(qǐng)求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ì)被丟棄念脯。
降級(jí)從系統(tǒng)功能優(yōu)先級(jí)角度考慮如何應(yīng)對(duì)故障狞洋,而限流則從用戶訪問壓力的角度來考慮如何應(yīng)對(duì)故障。
-
常見限流方式
-
基于請(qǐng)求限流:指從外部請(qǐng)求的角度考慮限流绿店。常見的方式有:
- 限制總量:限制某個(gè)指標(biāo)的累積上限吉懊。比如直播間的用戶總數(shù)上限為100萬,超過后用戶無法進(jìn)入假勿。搶購商品數(shù)量為100借嗽,限制搶購用戶上限為1萬個(gè),超過或直接拒絕转培。
- 限制時(shí)間量:限制一段時(shí)間內(nèi)某個(gè)指標(biāo)的上限恶导。例如:一分鐘內(nèi)只允許1000個(gè)用戶訪問。每秒請(qǐng)求峰值為10萬浸须。
- 都需要找到合適的閥值:需要通過性能壓測來確定閥值或者逐步優(yōu)化惨寿。
基于資源限流:指從系統(tǒng)內(nèi)部考慮,找到影響性能的關(guān)鍵資源删窒,對(duì)其使用上限限制裂垦。常見的內(nèi)部資源有:連接數(shù)、文件句柄肌索、線程數(shù)蕉拢、請(qǐng)求隊(duì)列、CPU利用率等。例如晕换,使用Netty實(shí)現(xiàn)服務(wù)器午乓,每個(gè)請(qǐng)求先放到請(qǐng)求隊(duì)列中,業(yè)務(wù)線程從請(qǐng)求隊(duì)列中獲取任務(wù)進(jìn)行處理闸准,請(qǐng)求隊(duì)列大小為1000硅瞧,那么超過該值則直接拒絕。
-
排隊(duì)
排隊(duì)方式來應(yīng)對(duì)接口級(jí)故障的方式是:讓用戶等待一段時(shí)間恕汇,而不是像限流方式直接拒絕用戶腕唧。從體驗(yàn)上來講,雖然用戶沒有很快得到拒絕響應(yīng)瘾英,但是如果等待時(shí)間過長枣接,體驗(yàn)也不是很好。(但是對(duì)于一些請(qǐng)求缺谴,等待比直接拒絕要好但惶,比如支付請(qǐng)求,排隊(duì)總比直接拒絕好湿蛔,因?yàn)橹苯泳芙^用戶就有可能不買了)
- 實(shí)現(xiàn)方式:排隊(duì)需要保存未被處理的請(qǐng)求膀曾,所以排隊(duì)需要緩存大量數(shù)據(jù),一般單個(gè)系統(tǒng)無法緩存這么多數(shù)據(jù)阳啥,所有需要單獨(dú)的排隊(duì)系統(tǒng)去實(shí)現(xiàn)添谊。例如使用Kafka、RocketMQ等消息隊(duì)列來緩存用戶的請(qǐng)求察迟。
實(shí)現(xiàn)思路:藍(lán)色區(qū)域是排隊(duì)系統(tǒng)
【排隊(duì)模塊】
負(fù)責(zé)將用戶的請(qǐng)求以FIFO的方式存入隊(duì)列中斩狱,不同商品的秒殺請(qǐng)求放在不同的隊(duì)列中,隊(duì)列大小可以根據(jù)秒殺商品數(shù)量自行定義扎瓶。
【調(diào)度模塊】
負(fù)責(zé)動(dòng)態(tài)調(diào)度排隊(duì)模塊中的請(qǐng)求到服務(wù)模塊中所踊。動(dòng)態(tài)性體現(xiàn)在:會(huì)根據(jù)服務(wù)模塊的當(dāng)前處理能力控制拉取請(qǐng)求速度,如果服務(wù)模塊的處理能力有空閑就提升拉取請(qǐng)求速度概荷,否則降慢速度秕岛。
【服務(wù)模塊】
負(fù)責(zé)調(diào)用真正的業(yè)務(wù)來處理請(qǐng)求,并獲取返回結(jié)果误证,再調(diào)用排隊(duì)模塊的接口寫回業(yè)務(wù)處理結(jié)果继薛。
案例
如果你來設(shè)計(jì)一個(gè)整點(diǎn)限量秒殺系統(tǒng),包括登錄雷厂、搶購惋增、支付(依賴支付寶)等核心功能,你會(huì)如何設(shè)計(jì)接口級(jí)的故障應(yīng)對(duì)手段改鲫?
- 思路:
丟車保帥:在秒殺時(shí)诈皿,通過服務(wù)降級(jí)把注冊(cè)林束、修改個(gè)人信息等非核心功能關(guān)閉掉。(是否為核心此時(shí)的判斷標(biāo)準(zhǔn)為:秒殺時(shí)間段這些功能影響人數(shù)少)
熔斷:支付依賴第三方服務(wù)稽亏,要設(shè)置熔斷策略壶冒,熔斷后要給出友好提示,比如10分鐘后再來支付截歉。
排隊(duì)+限流:搶購下單接口采用排隊(duì)+限流方式胖腾,如搶購1000件商品,則設(shè)置2000大小的隊(duì)列瘪松,請(qǐng)求超過2000后直接拒絕掉咸作,前2000請(qǐng)求加入隊(duì)列中,然后可以開啟多線程對(duì)隊(duì)列進(jìn)行處理宵睦。
作者:zlcook
鏈接:http://www.reibang.com/p/33f394c0ee2d
來源:簡書
著作權(quán)歸作者所有记罚。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處壳嚎。