日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

微服务架构-系统可靠性保障

發(fā)布時(shí)間:2023/12/29 windows 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 微服务架构-系统可靠性保障 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.可靠性

可靠性(Reliability)是指微服務(wù)系統(tǒng)在面對(duì)異常情況時(shí),如關(guān)鍵組件損壞、流量或數(shù)據(jù)量異常、延遲波動(dòng)、級(jí)聯(lián)故障傳導(dǎo)、分布式集群雪崩、系統(tǒng)過載等等,能夠持續(xù)保持穩(wěn)定運(yùn)行或快速恢復(fù)的能力。

當(dāng)我們?cè)谡f可靠性時(shí),我們到底在談什么?是指高可用架構(gòu)設(shè)計(jì)?系統(tǒng)容忍宕機(jī)的時(shí)間?彈性能力、自愈能力?還是指故障的轉(zhuǎn)移和恢復(fù)時(shí)間?

本文試圖從以下幾個(gè)方面來說明一個(gè)高可用架構(gòu)所需的必備因素:概念與度量、故障體系、單點(diǎn)治理、超時(shí)、重試、限流、降級(jí)、熔斷、Oncall 輪值與變更管理。

相信在這些方法論和實(shí)戰(zhàn)經(jīng)驗(yàn)相結(jié)合、多管齊下的協(xié)助下,能最大限度改善和保障系統(tǒng)的可靠性,讓微服務(wù)系統(tǒng)可以固若金湯,具備較強(qiáng)的韌性。

1.1.概念與度量

首先需要說明的是,我們?cè)谡劶翱煽啃詴r(shí),往往會(huì)把以下幾個(gè)相關(guān)的概念弄混淆:可靠性、可用性、彈性、持久性、冗余性。這些似乎都是和系統(tǒng)穩(wěn)定性有關(guān)的近義詞,但實(shí)際上是存在區(qū)別的。

1. 可靠性(Reliability)。可靠性是指系統(tǒng)能夠正常工作和穩(wěn)定運(yùn)行的時(shí)間,這里的穩(wěn)定性代表功能性操作正確無誤,且性能表現(xiàn)符合預(yù)期。

2. 可用性(Availability)。可用性是指系統(tǒng)可觸達(dá)的時(shí)間,一般是指服務(wù)或數(shù)據(jù)能夠連續(xù)提供給用戶的時(shí)間,或可用時(shí)間的占比。

3. 彈性(Resiliency)。彈性本質(zhì)上是指一種修復(fù)能力,代表系統(tǒng)在組件失敗或遇到災(zāi)難后的恢復(fù)能力。彈性能力一般由系統(tǒng)故障修復(fù)時(shí)間來衡量。

4. 持久性(Durability)。持久性是指數(shù)據(jù)能否具備持久化、穩(wěn)定存儲(chǔ)的能力,不會(huì)隨著時(shí)間變動(dòng)而輕易流失。和服務(wù)不同,持久性更側(cè)重于數(shù)據(jù)層面的穩(wěn)定性。

5. 冗余性(Redundancy)。冗余性是指系統(tǒng)是否存在多個(gè)副本,互為備份,也稱為系統(tǒng)的冗余度。冗余度越高,系統(tǒng)的災(zāi)備能力就越強(qiáng)。

舉個(gè)綜合的例子來說明,假設(shè)有一個(gè)視頻網(wǎng)站,對(duì)用戶提供 7*24 小時(shí)視頻展示和播放服務(wù)。該視頻網(wǎng)站具備以下特征:

  • 該網(wǎng)站每年頂多宕機(jī) 5 分鐘;
  • 經(jīng)常會(huì)出現(xiàn)頁面加載不完整,比如會(huì)出現(xiàn) CSS 無法加載而導(dǎo)致的頁面參差不齊;
  • 視頻偶爾會(huì)出現(xiàn)播放到一半的時(shí)候,出現(xiàn)長時(shí)間卡頓;
  • 該網(wǎng)站在請(qǐng)求延遲升高的時(shí)候,能在 1 分鐘內(nèi)迅速恢復(fù);
  • 該網(wǎng)站的數(shù)據(jù)做了完整的冷備,備份介質(zhì)采用磁帶和光盤,且異地保存。任何時(shí)候都可以快速恢復(fù)數(shù)據(jù);
  • 網(wǎng)站采用了異地多活的物理架構(gòu)部署,服務(wù)器和中間件采用 N+3 的 Buffer 來設(shè)計(jì);

不難看出,該視頻網(wǎng)站具備很高的可用性,因?yàn)殄礄C(jī)時(shí)間足夠短,用戶幾乎在任何時(shí)候都可以訪問。但是可靠性比較糟糕,因?yàn)轫撁娼?jīng)常無法正常加載,視頻播放體驗(yàn)也不盡如人意。網(wǎng)站的彈性恢復(fù)能力很強(qiáng),不到 1 分鐘就能從故障中恢復(fù)。另外,網(wǎng)站具備很優(yōu)秀的數(shù)據(jù)持久化能力,由于備份和恢復(fù)的存在,數(shù)據(jù)幾乎不用擔(dān)心丟失。網(wǎng)站的冗余度能達(dá)到 N+3,意味著系統(tǒng)架構(gòu)具備較高的災(zāi)備程度。

以上這些概念,通常來說在不同的上下文中具備不同的釋義。除非特別說明,默認(rèn)情況下本文不會(huì)有意區(qū)分這些名詞術(shù)語,而是統(tǒng)一采用廣義的可靠性概念來表達(dá)系統(tǒng)穩(wěn)定性語義。

可靠性的常見度量指標(biāo),是基于系統(tǒng)可用時(shí)間計(jì)算出來的比例,即 R(%) =? (uptime/uptime + downtime) ?* 100%,常見的 SLA 指標(biāo)會(huì)借助多少個(gè) 9 來表示,如圖 1?1 所示。

圖 1?1 常見 SLA 指標(biāo)

還有一種可靠性度量指標(biāo)是利用 MTTR、MTTF 和 MTBR 來表示,如圖 1?2 所示。

  • MTTR ( Mean Time To Repair),平均故障修復(fù)時(shí)間。指系統(tǒng)從發(fā)生故障到故障修復(fù)的時(shí)間間隔之平均值;
  • MTTF ( Mean Time To Failure),平均無故障時(shí)間。指系統(tǒng)從正常運(yùn)行到故障發(fā)生的時(shí)間間隔之平均值;
  • MTBF ( Mean Time Between Failure),平均故障間隔時(shí)間。指系統(tǒng)在兩次故障發(fā)生之間的時(shí)間間隔之平均值;

圖 1?2 MTTR、MTTF 和 MTBR 的關(guān)系

這種度量指標(biāo)下,可靠性通常用 R(%)? = (MTTF/MTBR)? * 100%? =? (MTTF/MTTR + MTTF) * 100%來表示。

SLA 指標(biāo)每提升一個(gè) 9,背后就需要付出較大的努力和人力、資源消耗。一般來說,大部分互聯(lián)網(wǎng)企業(yè)的關(guān)鍵業(yè)務(wù)可以達(dá)到 4 個(gè) 9,部分金融級(jí)別的業(yè)務(wù)系統(tǒng)或公有云會(huì)承諾 5 個(gè) 9。對(duì)大部分企業(yè)來說,需要根據(jù)自身的實(shí)力和業(yè)務(wù)需要,合理評(píng)估 SLA 需求,不要一味的去追求極高的 SLA,其投資回報(bào)比(ROI)可能并不高。

1.2.故障體系

故障體系是一套科學(xué)的方法論,用于指導(dǎo)和管理日常的系統(tǒng)故障。根據(jù)互聯(lián)網(wǎng)企業(yè)的實(shí)踐經(jīng)驗(yàn)總結(jié),再結(jié)合 Google SRE 標(biāo)準(zhǔn),我們?cè)囍o出一個(gè)標(biāo)準(zhǔn)的、完整的故障管理體系,包括:故障畫像、故障預(yù)案、故障演練、故障轉(zhuǎn)移、故障恢復(fù)。

1.2.1.故障畫像

故障畫像是故障體系和故障處理流程的源頭及理論依據(jù),所有線上問題的發(fā)生、發(fā)現(xiàn)和處理幾乎都是率屬于故障畫像所窮舉的各種范疇。

故障畫像本質(zhì)上來說就是通過分析大量的故障案例,進(jìn)行充分總結(jié)和高度抽象得出的故障根因(Root Cause)。常見的故障畫像大概分為以下幾類:

1. 基礎(chǔ)設(shè)施

常見的基礎(chǔ)設(shè)施故障包括以下組成部分:

機(jī)房設(shè)施故障:如電力系統(tǒng)故障、空調(diào)系統(tǒng)故障等一系列 IDC 機(jī)房底層相關(guān)的環(huán)境因素。

服務(wù)器故障:常見的有物理機(jī)、虛擬機(jī)、容器的系統(tǒng)宕機(jī)和指標(biāo)異常。宕機(jī)包括計(jì)劃內(nèi)和計(jì)劃外,服務(wù)器指標(biāo)異常包括 CPU 使用率異常,內(nèi)存使用率過高,SWAP 過于頻繁、網(wǎng)絡(luò)、磁盤等設(shè)備 I/O 讀寫異常,中斷及上下文切換頻次過高等等。對(duì)于虛擬機(jī)、容器來說,還會(huì)存在資源超賣導(dǎo)致的流量高峰期系統(tǒng)平均負(fù)載頻繁抖動(dòng)。

網(wǎng)絡(luò)故障:網(wǎng)絡(luò)問題是影響面最大的故障因素,往往會(huì)導(dǎo)致 P0 級(jí)別的生產(chǎn)事故。常見的有網(wǎng)絡(luò)中斷、丟包、重復(fù)、延遲、交換機(jī)路由器等設(shè)備故障、網(wǎng)絡(luò)專線故障等等。

接入層故障:常見的問題有 DNS 解析失敗、負(fù)載均衡 SLB 故障、VIP 轉(zhuǎn)移故障、Nginx 請(qǐng)求轉(zhuǎn)發(fā)異常(如路徑解析錯(cuò)誤、健康檢查機(jī)制失敗)等。

2. 中間件故障

常見的中間件故障包括以下組成部分:

存儲(chǔ)系統(tǒng)故障:一般指數(shù)據(jù)庫(MySQL、MongoDB、HBase、Cassandra 等 SQL 或 NoSQL 數(shù)據(jù)庫)、緩存、分布式存儲(chǔ)系統(tǒng)、分布式對(duì)象系統(tǒng)(OSS)等廣義上的存儲(chǔ)系統(tǒng)存在的故障點(diǎn),如:系統(tǒng)單點(diǎn),存儲(chǔ)系統(tǒng)只部署了單實(shí)例或單機(jī)房。這這種情況下,如果發(fā)生單實(shí)例宕機(jī)或單機(jī)房故障,或單實(shí)例讀寫流量過高、數(shù)據(jù)量較大導(dǎo)致的慢查詢、Load 升高等負(fù)載問題,由于沒有更多的冗余,使得系統(tǒng)無法進(jìn)行故障轉(zhuǎn)移。

消息中間件故障:作為削峰填谷和解耦的利器,消息中間件被大量使用在異步化場景中。但消息中間件并不能保證長久穩(wěn)定運(yùn)行。如:數(shù)據(jù)量過大導(dǎo)致磁盤被填滿,從而使得集群不可用;讀寫壓力過大導(dǎo)致 MQ 集群出現(xiàn) GC 頻繁、節(jié)點(diǎn)脫離集群等故障,如 ActiveMQ 的 Network Broker 模式,很容易在大流量的讀寫壓力下導(dǎo)致 Broker 斷開連接,影響到總體可用性。

3. 外部服務(wù)

一般是指第三方服務(wù)(如 REST API/RPC/消息等)的故障,如服務(wù)超時(shí)、HTTP 響應(yīng)狀態(tài)碼異常、服務(wù)過載、返回報(bào)文異常等。這類故障是出現(xiàn)頻次最高的,需要有重點(diǎn)預(yù)案、演練和監(jiān)控。

4. 系統(tǒng)缺陷

一般是指我們服務(wù)自身的功能、性能或穩(wěn)定性問題,如:JVM 內(nèi)存溢出、頻繁 GC 停頓、代碼死循環(huán)、CPU/內(nèi)存/磁盤使用率異常、系統(tǒng)過載、響應(yīng)時(shí)間過高、功能性 BUG 等。

5. 流程問題

流程問題一般是人為誤操作或流程不夠標(biāo)準(zhǔn)造成的故障,如代碼缺少 Code Review、缺乏漸進(jìn)式灰度發(fā)布機(jī)制、缺乏充分的功能或性能測(cè)試、缺乏監(jiān)控告警等。這類問題應(yīng)該盡量避免。

1.2.2.故障預(yù)案

凡事預(yù)則立,不預(yù)則廢。針對(duì)上一節(jié)描述的基礎(chǔ)設(shè)施、中間件、外部服務(wù)、系統(tǒng)缺陷和流程問題等故障畫像,我們需要擬定一套成熟的故障應(yīng)對(duì)預(yù)案。目標(biāo)是在故障突發(fā)時(shí),能夠使故障處理流程做到有章可依、有條不紊、敏捷高效。

以下是筆者結(jié)合自身的實(shí)際經(jīng)驗(yàn)總結(jié),整理出的一個(gè)故障預(yù)案模板,供參考:

1 基礎(chǔ)設(shè)施故障1.1 服務(wù)器故障【問題】宿主機(jī)(物理機(jī))故障導(dǎo)致的一個(gè)或多個(gè)虛擬機(jī)實(shí)例宕機(jī),或虛擬機(jī)發(fā)生計(jì)劃外(不明原因)的重啟;【預(yù)案】一個(gè)虛擬機(jī)實(shí)例宕機(jī)一般影響較小,確定負(fù)載均衡的自動(dòng)健康檢查已將流量轉(zhuǎn)走,待虛擬機(jī)恢復(fù)后重新部署應(yīng)用。注:正在調(diào)研服務(wù)器重啟時(shí)自動(dòng)觸發(fā)Jenkins部署以減少人工運(yùn)維;【預(yù)案】多個(gè)虛擬機(jī)實(shí)例宕機(jī)需評(píng)估影響范圍,極端情況可能會(huì)造成流量擊垮其他服務(wù)器,緊急情況需啟用備用虛擬機(jī)。確定負(fù)載均衡的自動(dòng)健康檢查已將流量轉(zhuǎn)走; 【問題】服務(wù)器(包括物理機(jī)、虛擬機(jī)和容器)一項(xiàng)或多項(xiàng)指標(biāo)異常,如平均負(fù)載升高、內(nèi)存空間不足、磁盤空間不足、CPU消耗過高、I/O消耗過高、文件句柄泄露等,導(dǎo)致程序無法正常運(yùn)行;【預(yù)案】在基礎(chǔ)監(jiān)控系統(tǒng)中查看服務(wù)器指標(biāo)變化情況;【預(yù)案】根據(jù)指標(biāo)變化找到原因,解決問題。如程序中資源釋放、JVM調(diào)優(yōu)、清磁盤機(jī)制優(yōu)化等; 1.2 網(wǎng)絡(luò)故障【問題】機(jī)房網(wǎng)絡(luò)誤操作(網(wǎng)絡(luò)割接/板卡升級(jí)替換/打補(bǔ)丁/設(shè)備升級(jí)/配置優(yōu)化/擴(kuò)容/虛擬網(wǎng)絡(luò)組件升級(jí)等),或部分網(wǎng)絡(luò)設(shè)備故障,造成一臺(tái)或多臺(tái)服務(wù)器級(jí)別網(wǎng)絡(luò)問題(內(nèi)網(wǎng)不通、丟包、延遲等);【預(yù)案】將問題反饋到網(wǎng)絡(luò)組;【預(yù)案】一臺(tái)服務(wù)器網(wǎng)絡(luò)問題一般影響較小,確定負(fù)載均衡的自動(dòng)健康檢查已將流量轉(zhuǎn)走,并關(guān)注網(wǎng)絡(luò)恢復(fù)情況;【預(yù)案】多臺(tái)服務(wù)器網(wǎng)絡(luò)問題需評(píng)估影響范圍,必要情況需要切流量。確定負(fù)載均衡的自動(dòng)健康檢查已將流量轉(zhuǎn)走; 【問題】機(jī)房核心交換機(jī)等大型故障,造成子網(wǎng)級(jí)別網(wǎng)絡(luò)問題,或機(jī)房級(jí)別網(wǎng)絡(luò)問題;【預(yù)案】將問題反饋到網(wǎng)絡(luò)組;【預(yù)案】若網(wǎng)絡(luò)故障影響到負(fù)載均衡SLB,則通過控制臺(tái)修改DNS配置,將流量導(dǎo)向其他正常SLB,并等待DNS緩存更新;【預(yù)案】若影響到轉(zhuǎn)發(fā)前置機(jī)Nginx,通過SLB配置后臺(tái),將流量導(dǎo)向其他正常Nginx;【預(yù)案】若影響到服務(wù)器,通過Nginx配置將流量導(dǎo)向其他正常的服務(wù)器; 【問題】運(yùn)營商問題或網(wǎng)絡(luò)流量過大,造成專線問題,或?qū)>€帶寬打滿;【預(yù)案】將問題反饋到網(wǎng)絡(luò)組;【預(yù)案】參考上面預(yù)案; 1.3 電力故障【問題】機(jī)房例行檢修(倒閘檢修/柴油發(fā)電帶載等)導(dǎo)致故障,或意外停電故障,造成機(jī)房無法正常運(yùn)行;【預(yù)案】若影響到負(fù)載均衡SLB,則通過控制臺(tái)修改DNS配置,將流量導(dǎo)向其他正常SLB,并等待DNS緩存更新;【預(yù)案】若影響到Nginx,通過SLB配置將流量導(dǎo)向其他正常Nginx; 1.4 接入層故障【問題】DNS故障,無法解析【預(yù)案】公司層面報(bào)障,切換客戶端DNS高可用配置,開啟備用DNS域名; 【問題】SLB故障,如VIP無法訪問,或丟包;【預(yù)案】通知SLB運(yùn)維人員;【預(yù)案】SLB部署需要做到:1)外網(wǎng):同一個(gè)運(yùn)營商出口會(huì)配置2個(gè)不同機(jī)房SLB,2)內(nèi)網(wǎng):同一個(gè)內(nèi)網(wǎng)域名會(huì)配置多個(gè)不同機(jī)房SLB用于冷備;【預(yù)案】通過控制臺(tái)修改DNS將流量導(dǎo)向其他正常SLB,并等待DNS緩存更新 ; 【問題】Nginx故障;【預(yù)案】Nginx前置機(jī)部署時(shí)需要跨機(jī)房;【預(yù)案】通過SLB配置將流量導(dǎo)向其他正常Nginx; 2 中間件故障2.1 存儲(chǔ)故障【問題】MySQL故障,無法訪問或訪問超時(shí);【預(yù)案】要求部署時(shí)必須是Master-Slave架構(gòu)且跨機(jī)房;【預(yù)案】遇到單實(shí)例故障或機(jī)房故障時(shí),會(huì)自動(dòng)進(jìn)行Failover且切換主從,業(yè)務(wù)方會(huì)經(jīng)歷一段有損服務(wù)后自行恢復(fù); 【問題】MongoDB故障,無法訪問或訪問超時(shí);【預(yù)案】要求部署時(shí)必須是跨機(jī)房;【預(yù)案】遇到單實(shí)例故障時(shí),會(huì)自動(dòng)進(jìn)行Failover且重新選舉Primary,業(yè)務(wù)方會(huì)經(jīng)歷一段有損服務(wù)后自行恢復(fù); 【問題】HBase故障,無法訪問或訪問超時(shí);需要封裝客戶端代理SDK(內(nèi)置配置中心開關(guān)),底層做雙向數(shù)據(jù)復(fù)制;遇到集群故障時(shí),通過配置中心切換到另一個(gè)集群; 【問題】Couchbase故障,無法訪問或訪問超時(shí);需要封裝客戶端代理SDK(內(nèi)置配置中心開關(guān)),底層做XDCR數(shù)據(jù)復(fù)制;遇到集群故障時(shí),通過配置中心切換到另一個(gè)集群; 【問題】Redis故障,無法訪問或訪問超時(shí);【預(yù)案】要求部署必須是Master-Slave架構(gòu)且跨機(jī)房;【預(yù)案】遇到到單實(shí)例故障時(shí),會(huì)自動(dòng)進(jìn)行Failover且切換主從,業(yè)務(wù)方會(huì)經(jīng)歷一段有損服務(wù)后自行恢復(fù); 2.2 搜索系統(tǒng)故障【問題】Elasticsearch故障,無法訪問或訪問超時(shí)【預(yù)案】通過客戶端代理組件,將讀寫流量切換到備用Elasticsearch集群; 2.3 消息中間件故障【問題】ActiveMQ故障,無法訪問或訪問超時(shí)【預(yù)案】通過客戶端代理組件,將讀寫流量切換到備用ActiveMQ集群; 【問題】Kafka故障,無法訪問或訪問超時(shí)【預(yù)案】通過客戶端代理組件,將讀寫流量切換到備用Kafka集群; 2.4 分布式系統(tǒng)故障【問題】Zookeeper故障,無法訪問或訪問超時(shí);【預(yù)案】等待Zookeeper完成奔潰恢復(fù)和重新選舉,密切觀察監(jiān)控指標(biāo)變化; 3.外部服務(wù)故障【問題】外部服務(wù)出現(xiàn)調(diào)用超時(shí)或異常返回;【預(yù)案】在編碼時(shí)務(wù)必處理好第三方調(diào)用的超時(shí)、重試、降級(jí)與熔斷機(jī)制,做好監(jiān)控告警與日志埋點(diǎn),并對(duì)異常情況做好測(cè)試;【預(yù)案】遇到故障時(shí),啟動(dòng)手動(dòng)或自動(dòng)降級(jí)熔斷,使得調(diào)用快速失敗和快速返回兜底數(shù)據(jù),避免調(diào)用鏈雪崩;

復(fù)制

1.2.3.故障演練與混沌工程

光說不練假把式。故障演練是整個(gè)故障管理體系中最重要的一環(huán)。缺乏真實(shí)演練尤其是生產(chǎn)環(huán)境的真實(shí)故障演練,故障預(yù)案則一文不值。線上環(huán)境的故障演練能真實(shí)反映系統(tǒng)的潛在故障點(diǎn),驗(yàn)證監(jiān)控、告警及日志系統(tǒng)的及時(shí)性和有效性,也能高效驗(yàn)證故障預(yù)案和處理流程的實(shí)戰(zhàn)效果。

企業(yè)、部門乃至業(yè)務(wù)團(tuán)隊(duì)?wèi)?yīng)該成立故障演練小組,制定完備的演練規(guī)劃、方案和執(zhí)行計(jì)劃,定期或不定期進(jìn)行生產(chǎn)環(huán)境的演練,并生成故障演練報(bào)告和跟蹤項(xiàng),做到及時(shí)發(fā)現(xiàn)和解決各種故障隱患。

隨著 Netflix 的 Chaos Engineering 思想和部分頭部互聯(lián)網(wǎng)公司的實(shí)踐(如阿里的 Chaos Blade),混沌工程開始進(jìn)入了國內(nèi)眾多工程師的視野,風(fēng)靡大江南北,且有愈演愈烈的趨勢(shì)。混沌工程的基本原則主要有:

  • 建立穩(wěn)定狀態(tài)的假設(shè);
  • 多樣化現(xiàn)實(shí)世界事件;
  • 在生產(chǎn)環(huán)境運(yùn)行實(shí)驗(yàn);
  • 持續(xù)自動(dòng)化運(yùn)行實(shí)驗(yàn);
  • 最小化“爆炸半徑”;

我們可以根據(jù)混沌工程的方法論和工具包,探索和開發(fā)自動(dòng)化混沌測(cè)試方案,支持基礎(chǔ)設(shè)施、中間件、服務(wù)的自動(dòng)故障注入和測(cè)試。通過在生產(chǎn)環(huán)境設(shè)置定時(shí)器,可以支持預(yù)先編排好的混沌測(cè)試用例自動(dòng)化執(zhí)行,可以盡早發(fā)現(xiàn)系統(tǒng)的可靠性隱患。以上操作可以在混沌測(cè)試平臺(tái)上進(jìn)行開發(fā)、配置、部署、自動(dòng)化運(yùn)行和監(jiān)控。

以下是根據(jù)一個(gè)實(shí)際生

產(chǎn)環(huán)境故障注入案例,經(jīng)過整理得到的混沌測(cè)試用例:

1.模擬虛擬機(jī)VM CPU滿載時(shí)間:2021-08-20 00:00~00:30執(zhí)行:8核CPU使用率均達(dá)到100%期望:基礎(chǔ)監(jiān)控可觀察到CPU使用率上升,系統(tǒng)告警。應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。負(fù)載均衡自動(dòng)摘除不健康節(jié)點(diǎn)。 2.模擬虛擬機(jī)VM 內(nèi)存完全占用時(shí)間:2021-08-20 00:30~01:00執(zhí)行:32GB RAM使用率達(dá)到100%期望:基礎(chǔ)監(jiān)控可觀察到MEM使用率上升,系統(tǒng)告警。應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。負(fù)載均衡自動(dòng)摘除不健康節(jié)點(diǎn)。 3.模擬虛擬機(jī)VM 磁盤I/O完全占用時(shí)間:2021-08-20 01:00~01:30執(zhí)行:磁盤I/O使用率達(dá)到100%期望:基礎(chǔ)監(jiān)控可觀察到磁盤I/O使用率上升,系統(tǒng)告警。應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。負(fù)載均衡自動(dòng)摘除不健康節(jié)點(diǎn)。 4.模擬虛擬機(jī)VM 磁盤完全填充時(shí)間:2021-08-20 01:30~02:00執(zhí)行:300GB磁盤使用率達(dá)到100%期望:基礎(chǔ)監(jiān)控可觀察到磁盤使用率上升,系統(tǒng)告警,無法寫入。應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。負(fù)載均衡自動(dòng)摘除不健康節(jié)點(diǎn)。 5.模擬虛擬機(jī)VM 宕機(jī)時(shí)間:2021-08-20 02:00~02:30執(zhí)行:將該虛擬機(jī)實(shí)例關(guān)閉期望:基礎(chǔ)監(jiān)控可觀察到虛機(jī)關(guān)閉,系統(tǒng)告警。應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。負(fù)載均衡自動(dòng)摘除不健康節(jié)點(diǎn)。 6.模擬Kubernetes Pod宕機(jī)時(shí)間:2021-08-20 02:30~03:00執(zhí)行:將某Workload下的Pod關(guān)閉期望:基礎(chǔ)監(jiān)控可觀察到虛機(jī)關(guān)閉,系統(tǒng)告警。應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。負(fù)載均衡自動(dòng)摘除不健康節(jié)點(diǎn)。Kubernetes自動(dòng)啟動(dòng)新的Pod。 7.模擬不同物理機(jī)的虛擬機(jī)、Pod宕機(jī)時(shí)間:2021-08-20 03:00~03:30執(zhí)行:將隸屬于不同物理機(jī)的虛擬機(jī)和Pod關(guān)閉期望:基礎(chǔ)監(jiān)控可觀察到虛機(jī)關(guān)閉,系統(tǒng)告警。應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。負(fù)載均衡自動(dòng)摘除不健康節(jié)點(diǎn)。Kubernetes自動(dòng)啟動(dòng)新的Pod。 8.模擬單機(jī)房網(wǎng)絡(luò)故障時(shí)間:2021-08-20 03:30~04:00執(zhí)行:通過模擬網(wǎng)絡(luò)延遲、丟包、專線斷開等方式,實(shí)現(xiàn)單一機(jī)房網(wǎng)絡(luò)通訊故障期望:基礎(chǔ)監(jiān)控可觀察到虛機(jī)關(guān)閉,系統(tǒng)告警。應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。 9.模擬MySQL故障時(shí)間:2021-08-20 04:00~04:30執(zhí)行:將MySQL Master節(jié)點(diǎn)和Slave節(jié)點(diǎn)分別關(guān)閉期望:基礎(chǔ)監(jiān)控可觀察到虛機(jī)關(guān)閉,系統(tǒng)告警。應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。MySQL主從集群自動(dòng)提升Slave為主節(jié)點(diǎn),并自動(dòng)修改域名綁定。應(yīng)用層面感知不明顯。 10.模擬推薦服務(wù)故障時(shí)間:2021-08-20 04:30~05:00執(zhí)行:通過制造網(wǎng)絡(luò)延遲及丟包,模擬推薦服務(wù)故障期望:應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。推薦服務(wù)(強(qiáng)依賴服務(wù))被自動(dòng)降級(jí)到緩存數(shù)據(jù),推薦效果出現(xiàn)折損。 11.模擬用戶服務(wù)故障時(shí)間:2021-08-20 05:00~05:30執(zhí)行:通過制造網(wǎng)絡(luò)延遲及丟包,模擬用戶服務(wù)故障期望:應(yīng)用監(jiān)控顯示該節(jié)點(diǎn)工作不正常并及時(shí)告警。用戶服務(wù)被自動(dòng)熔斷,業(yè)面上大部分用戶的關(guān)鍵信息(如頭像、昵稱)出現(xiàn)丟失,主體服務(wù)不受影響。

復(fù)制

以上給出了一些基本的混沌測(cè)試注入案例,覆蓋了基礎(chǔ)設(shè)施(服務(wù)器、網(wǎng)絡(luò))、中間件(存儲(chǔ)系統(tǒng))和外部服務(wù)(強(qiáng)依賴服務(wù)、弱依賴服務(wù))等。實(shí)際執(zhí)行混沌測(cè)試時(shí),可參考這些案例,并靈活變動(dòng)。

1.2.4.故障轉(zhuǎn)移

根據(jù)墨菲定律,該發(fā)生的故障終究會(huì)發(fā)生。盡管我們做了大量的故障預(yù)案和演練,但只要系統(tǒng)存在薄弱環(huán)節(jié)(幾乎 100%無法避免),則遲早會(huì)被攻破,問題也會(huì)爆發(fā)。

在故障發(fā)生時(shí),故障轉(zhuǎn)移(Failover)手段就顯得尤為重要,好的轉(zhuǎn)移技術(shù)手段能有效縮短平均故障修復(fù)時(shí)間 MTTR,減少系統(tǒng)、數(shù)據(jù)、資金、公司信譽(yù)損失,也能將用戶體驗(yàn)影響降到最低。

故障轉(zhuǎn)移基本原理是利用 HA 監(jiān)控組件,實(shí)時(shí)追蹤和發(fā)現(xiàn)系統(tǒng)的故障點(diǎn),并自動(dòng)執(zhí)行故障點(diǎn)轉(zhuǎn)移,將服務(wù)流量和數(shù)據(jù)遷移到冗余的組件上。

需要說明的是,這里的組件是一個(gè)廣義的概念,可以是一個(gè)物理機(jī)、虛擬機(jī)、容器,也可以是一個(gè)集群或集群節(jié)點(diǎn),再大一點(diǎn)可以是 IDC 機(jī)房、AZ 可用區(qū)或地理位置 Region。

故障轉(zhuǎn)移主要有兩種模式:主動(dòng)-主動(dòng)模式和主動(dòng)-被動(dòng)模式。

主動(dòng)-主動(dòng)模式(Active-Active):主動(dòng)-主動(dòng)模式是指組件之間相互熱備,且正常承擔(dān)讀寫流量。在故障發(fā)生時(shí),HA 監(jiān)控組件檢測(cè)到不健康組件后,對(duì)其進(jìn)行摘除或屏蔽,避免流量訪問。

舉例來說明,常見的主動(dòng)-主動(dòng)模式有無狀態(tài)的服務(wù)器集群,或去中心化的存儲(chǔ)集群。

如 REST API 服務(wù)集群,多節(jié)點(diǎn)提供服務(wù),由接入層提供負(fù)載均衡、鑒權(quán)及流量路由。這種情況可以視為一種無狀態(tài)的主動(dòng)-主動(dòng)模式。當(dāng)單一節(jié)點(diǎn)或多個(gè)節(jié)點(diǎn)發(fā)生故障(宕機(jī)、服務(wù)器 CPU/MEM/DISK/NETWORK 指標(biāo)異常等)時(shí),由接入層的健康檢查組件自動(dòng)檢測(cè)出不健康狀態(tài)的節(jié)點(diǎn),并將這些節(jié)點(diǎn)從集群臨時(shí)剔除。

另一種情況是無中心的存儲(chǔ)集群,如 Couchbase。當(dāng)某一節(jié)點(diǎn)宕機(jī)后,集群會(huì)將該節(jié)點(diǎn)屏蔽,將讀寫流量轉(zhuǎn)移到其他節(jié)點(diǎn)。

主動(dòng)-被動(dòng)模式(Active-Passive):主動(dòng)-被動(dòng)模式是指備用組件平時(shí)不會(huì)提供服務(wù),僅充當(dāng)冷備的角色。當(dāng)故障發(fā)生時(shí),由 HA 監(jiān)控組件將不健康組件進(jìn)行摘除處理,同時(shí)將流量導(dǎo)入備用節(jié)點(diǎn)。

這種情況需要格外小心,很多時(shí)候備用節(jié)點(diǎn)往往只是在冷備和待命,在關(guān)鍵時(shí)刻可能會(huì)“掉鏈子”,不能正常工作。在故障切換時(shí),有時(shí)候會(huì)發(fā)生流量打到備用設(shè)備后,備用組件再次出現(xiàn)問題,故障影響面反而被再次放大。

1.2.5.故障恢復(fù)

故障恢復(fù)是故障處理的收尾動(dòng)作,當(dāng)故障轉(zhuǎn)移完畢,就應(yīng)該對(duì)故障組件進(jìn)行及時(shí)修復(fù),這可能是一個(gè)手動(dòng)或自動(dòng)的處理過程。

故障組件恢復(fù)后,通常會(huì)面臨兩個(gè)選擇:將流量再次轉(zhuǎn)移回已恢復(fù)的組件,恢復(fù)到故障前的拓?fù)浣Y(jié)構(gòu);另一種方案就是將恢復(fù)的組件加入到總體架構(gòu),充當(dāng)備用角色。

故障恢復(fù)的時(shí)間應(yīng)該盡可能短,并且可控。因?yàn)楣收限D(zhuǎn)以后,系統(tǒng)總體可能會(huì)處于“單點(diǎn)”的狀態(tài),如果故障組件不能很快恢復(fù)并再次加入系統(tǒng),則又會(huì)增加長時(shí)間單點(diǎn)的風(fēng)險(xiǎn)。如果此時(shí)剩下的組件再次發(fā)生故障,系統(tǒng)就會(huì)出現(xiàn)無組件可轉(zhuǎn)移的問題。

舉一個(gè)實(shí)際生產(chǎn)環(huán)境發(fā)生的例子來說明。某 Feed 服務(wù)集群,物理架構(gòu)上采用 2 個(gè)機(jī)房來部署節(jié)點(diǎn),假設(shè)為 IDC1 和 IDC2。在某個(gè)晚高峰,IDC1 出現(xiàn)核心交換機(jī)網(wǎng)絡(luò)故障,所有服務(wù)器實(shí)例無法建立網(wǎng)絡(luò)連接,機(jī)房總體不可用,運(yùn)維人員緊急將 IDC1 從負(fù)載均衡設(shè)備上進(jìn)行摘除。

IDC1 在接下來的 2 天都沒有完全恢復(fù),不幸的事情發(fā)生了,IDC2 在另一個(gè)晚高峰也出現(xiàn)了網(wǎng)絡(luò)故障,這個(gè)系統(tǒng)徹底癱瘓了。

這里先不討論基礎(chǔ)架構(gòu)的薄弱及運(yùn)維能力的欠缺,單從故障恢復(fù)的層面來看,我們應(yīng)當(dāng)遵循“盡早恢復(fù)”的原則,將故障組件盡可能快速、高效的恢復(fù)和重新加入系統(tǒng)。

1.3.單點(diǎn)治理

從這一節(jié)開始,我們來逐步介紹提升微服務(wù)系統(tǒng)可靠性的手段。

分布式系統(tǒng)存在單點(diǎn)故障(Single?Point?of?Failure,SPOF),是故障頻發(fā)且無法收斂的一個(gè)重要原因。故障本身是不可避免的,但是當(dāng)問題發(fā)生時(shí),如果系統(tǒng)單點(diǎn)導(dǎo)致無法進(jìn)行及時(shí)的 Failover,則系統(tǒng)可靠性就會(huì)大打折扣。因此,系統(tǒng)的單點(diǎn)治理迫在眉睫,故障的單點(diǎn)治理水平也是衡量一個(gè)系統(tǒng)可靠性的重要指標(biāo)。

單點(diǎn)治理的核心思想是提升冗余度,不管是無狀態(tài)的服務(wù),還是有狀態(tài)的存儲(chǔ)、中間件,都可以通過冗余部署的方式,形成同構(gòu)、同質(zhì)的集群化架構(gòu),從而達(dá)到壓力分?jǐn)偂⒒ハ鄠浞菖c切換的效果。

1.3.1.組件類型與粒度

在梳理系統(tǒng)單點(diǎn)時(shí),必須要弄清楚系統(tǒng)組件的類型和粒度,這些內(nèi)容通常也代表了故障發(fā)生的顆粒度。常見的粒度有:

服務(wù)器:服務(wù)器是系統(tǒng)賴以生存的基本運(yùn)行時(shí)環(huán)境,通常包括物理機(jī)、虛擬機(jī)和容器。服務(wù)器的粒度可以簡單按物理機(jī)、機(jī)架、機(jī)柜、機(jī)房、地域來劃分。具體可歸納總結(jié)為:

  • 單臺(tái)物理機(jī)、單一虛擬機(jī)或容器實(shí)例;
  • 來自同一機(jī)架或機(jī)柜的多臺(tái)物理機(jī),來自同一物理機(jī)的多個(gè)虛擬機(jī)、容器實(shí)例;
  • 來自不同機(jī)架或機(jī)柜的多臺(tái)物理機(jī),來自不同物理機(jī)的多個(gè)虛擬機(jī)、容器實(shí)例;
  • 來自同一機(jī)房的多個(gè)物理機(jī)、虛擬機(jī)和容器;
  • 來自不同機(jī)房的多個(gè)物理機(jī)、虛擬機(jī)和容器;
  • 來自同一地域的多個(gè)物理機(jī)、虛擬機(jī)和容器;
  • 來自不同地域的多個(gè)物理機(jī)、虛擬機(jī)和容器;

中間件:中間件通常包括存儲(chǔ)(數(shù)據(jù)庫、緩存等)、消息中間件、搜索中間件、微服務(wù)組件等各類除服務(wù)器之外的基礎(chǔ)設(shè)施。中間件以單實(shí)例和集群化的部署架構(gòu)最為常見,集群化往往使用場景更普遍,很多中間件提供了原生的集群解決方案,如 Redis Cluster、Kafka、MongoDB、HBase、Elasticsearch 等;

中間件的實(shí)例本身也是由服務(wù)器構(gòu)成,這里不再重復(fù)贅述服務(wù)器的單點(diǎn)情況,而是直接列舉中間件的拓?fù)鋯吸c(diǎn):

  • 中間件只有單實(shí)例;
  • 中間件為集群架構(gòu),包含多實(shí)例,分布在同機(jī)房;
  • 中間件為集群架構(gòu),包含多實(shí)例,分布在同地域的不同機(jī)房;
  • 中間件為集群架構(gòu),包含多實(shí)例,分布在不同地域的不同機(jī)房;

現(xiàn)代的企業(yè)級(jí)、分布式物理架構(gòu)基本都是多機(jī)房、多可用區(qū)和多地理位置部署,本文觀點(diǎn)是,如果不特別指出,默認(rèn)的單點(diǎn)粒度至少是機(jī)房級(jí)別,即系統(tǒng)至少應(yīng)該跨機(jī)房部署,以及具備跨機(jī)房容災(zāi)能力。

從以上列舉的服務(wù)器和中間件組件的粒度可以看出,有很多種粒度類型其實(shí)是存在單點(diǎn)風(fēng)險(xiǎn)的,亟待治理。

如何進(jìn)行單點(diǎn)治理,提升系統(tǒng)冗余度、彈性和可用性?通常見仁見智,各企業(yè)、機(jī)構(gòu)、各架構(gòu)師的解決方案通常會(huì)不一樣,并沒有標(biāo)準(zhǔn)答案。本文試圖給出一種經(jīng)過實(shí)踐的冗余高可用方案,如圖 1?3 所示。

圖 1?3 一種跨地理位置的多數(shù)據(jù)中心物理架構(gòu)

這是一種在實(shí)際生產(chǎn)環(huán)境中驗(yàn)證過的多數(shù)據(jù)中心物理架構(gòu)。物理層面,由華北 Region 和華南 Region 組成,每個(gè) Region 又由 3 個(gè)物理 IDC 機(jī)房組成。邏輯層面,包括接入層、服務(wù)層和中間件組件。下面

來分析每一層的潛在單點(diǎn)故障風(fēng)險(xiǎn),以及對(duì)應(yīng)的冗余方案和故障轉(zhuǎn)移措施。

1.3.2.接入層高可用

接入層包括 DNS 域名智能解析、SLB 負(fù)載均衡以及 Nginx 反向代理。

DNS 域名解析:DNS 域名智能解析,根據(jù)用戶的地理位置和運(yùn)營商進(jìn)行智能解析,將請(qǐng)求流量引流到離用戶最近的 SLB 負(fù)載均衡 VIP 上。

通常會(huì)針對(duì)每一組 VIP,設(shè)置多個(gè) SLB 負(fù)載均衡互相熱備,流量可以打到任意一個(gè) SLB 上,這種方案既可以起到負(fù)載均衡、分?jǐn)倝毫Φ淖饔?#xff0c;還可以達(dá)到冗余、故障轉(zhuǎn)移的目的。

這樣做的好處可以使得用戶就近接入,避免跨地理位置處理請(qǐng)求事務(wù),造成不必要的延遲。比如北京移動(dòng)用戶,就會(huì)優(yōu)先訪問部署在北京移動(dòng)機(jī)房的 SLB 負(fù)載均衡。

DNS 智能解析故障包括兩方面:

1. 局部解析失效,或無法解析到正確的 VIP 上,如圖 1?3 中 1 所示。在實(shí)際環(huán)境中,偶爾會(huì)發(fā)生,特別容易發(fā)生在解析策略比較細(xì)的情況下。比如,北京聯(lián)通的用戶,可能會(huì)被解析位于河北機(jī)房的 VIP 上。還有一種情況是局部解析策略失效,如北京電信的用戶無法解析。

由于配置了多種解析策略以及多組 VIP(每組又包含了 N 個(gè) SLB 組件),因此,當(dāng)故障發(fā)生時(shí),完全可以通過調(diào)整 DNS 解析策略,將故障域的用戶請(qǐng)求解析到正常的 VIP 上。

2. DNS 域名解析完全失效,如圖 1?3 中 2 所示。這是一種極其嚴(yán)重、災(zāi)難性的單點(diǎn)故障,也是很容易被忽略的一種場景,會(huì)導(dǎo)致客戶端訪問完全無計(jì)可施,所有網(wǎng)站和 APP 頁面均無法加載。

一種常見的解決方案是采用多 DNS 域名機(jī)制。客戶端預(yù)先對(duì)服務(wù)端提供的 DNS 做冗余,埋點(diǎn)備用 DNS 域名,最好采用 2 個(gè)以上的備用域名。

當(dāng)故障發(fā)生時(shí),通過遠(yuǎn)程配置中心下發(fā)切換指令,進(jìn)行域名切換。或者客戶端會(huì)植入負(fù)載均衡和健康檢查算法,當(dāng)探測(cè)到當(dāng)前 DNS 域名不可訪問時(shí),可自動(dòng)切換到備用域名上,這種能力通常會(huì)被封裝成組件或 SDK,供客戶端透明的使用。

SLB 負(fù)載均衡:SLB 負(fù)載均衡主要是提供一個(gè)高可用的集群,對(duì)外通過 VIP 暴露訪問端點(diǎn)。通常采用硬件設(shè)備,或 LVS、HAProxy 之類的軟件實(shí)現(xiàn)。SLB 的重點(diǎn)是高可用的 VIP 機(jī)制,以及負(fù)載均衡、健康檢查、SSL 卸載機(jī)制,通常只做流量轉(zhuǎn)發(fā)。

SLB 的故障通常有兩種:

1. 單 SLB 故障,如圖 1?3 中 3 所示。通常是 VIP 漂移失敗導(dǎo)致。解決方案也很簡單,直接在 DSN 解析層面,將該 SLB 的 VIP 摘除即可。業(yè)務(wù)層面需要接受短暫的 DNS 緩存帶來的請(qǐng)求失敗問題。

2.多 SLB 故障,如圖 1?3 中 4 所示。這種情況不常見,通常是多個(gè) SLB 部署在一個(gè)物理相關(guān)的設(shè)備下導(dǎo)致,如共享一個(gè)機(jī)架機(jī)柜、共享一個(gè)機(jī)房或網(wǎng)絡(luò)設(shè)備。在故障預(yù)案層面,需要將多 SLB 進(jìn)行合理的分散部署,至少需要跨 2 個(gè)機(jī)房。

當(dāng)問題發(fā)生時(shí),由于我們有多組 SLB,可以修改 DNS 解析策略,將故障組進(jìn)行隔離,流量導(dǎo)入其他組 SLB 即可。

Nginx 反向代理:Nginx 反向代理的作用主要是提供限流、黑白名單、鑒權(quán)、流量轉(zhuǎn)發(fā)、監(jiān)控、日志等功能,也是眾多 API 網(wǎng)關(guān)得以實(shí)現(xiàn)的基礎(chǔ)組件(如 OpenResty、 Kong)。

Nginx 的物理部署架構(gòu)和 SLB 完全不同,一般是按業(yè)務(wù)機(jī)房進(jìn)行部署的,作為業(yè)務(wù)系統(tǒng)在當(dāng)前機(jī)房的前置機(jī)。這樣做的好處是,一旦發(fā)生機(jī)房級(jí)別故障,直接摘除 Nginx 集群即可快速對(duì)流量進(jìn)行阻斷和隔離。

Nginx 反向代理的單點(diǎn)故障通常有兩種:

1. Nginx 單機(jī)故障,如圖 1?3 中 5 所示。這種情況很常見,因?yàn)?Nginx 本身也是借助服務(wù)器建立的服務(wù),服務(wù)器的各種問題當(dāng)然也會(huì)導(dǎo)致 Nginx 故障。解決方案也很簡單,由上層的 SLB 通過健康檢查,自動(dòng)摘除即可。

2.一組 Nginx 故障,如圖 1?3 中 6 所示。通常由軟件 BUG 或機(jī)房級(jí)別故障導(dǎo)致,這種問題發(fā)生比例不高,但確實(shí)會(huì)存在。解決方案是由 SLB 自動(dòng)摘除該組 Nginx,流量自動(dòng)被旁路到其他機(jī)房。

1.3.3.服務(wù)層高可用

這里的服務(wù)層一般指無狀態(tài)業(yè)務(wù)集群,即任何一個(gè)服務(wù)實(shí)例均不存儲(chǔ)數(shù)據(jù),除了一些可隨時(shí)失效(Invalidate)或剔除(Evict)的本地緩存,以及寫入本地磁盤的日志日志。業(yè)務(wù)集群無狀態(tài)的好處是顯而易見的,可以有效的提升系統(tǒng)靈活性、伸縮性和故障轉(zhuǎn)移速度。

服務(wù)層的單點(diǎn)問題有兩種:

1. 單一服務(wù)器實(shí)例故障,如圖 1?3 中 9 所示。一般是由服務(wù)器自身的故障點(diǎn)導(dǎo)致,這種問題的發(fā)生概率非常高,當(dāng)集群規(guī)模達(dá)到 1000 以上的實(shí)例時(shí),幾乎每天都會(huì)隨機(jī)出現(xiàn) 1~5 個(gè)實(shí)例故障。

當(dāng)單一實(shí)例故障時(shí),通常不需要采取任何手動(dòng)措施,而是由上層的 Nginx 代理通過健康檢查來自動(dòng)摘除不健康實(shí)例。

2. 多服務(wù)器實(shí)例故障,如圖 1?3 中 10 所示。一般是虛擬機(jī)、容器對(duì)應(yīng)的宿主機(jī)故障導(dǎo)致,當(dāng)然也可能會(huì)由程序 BUG 觸發(fā)或性能問題導(dǎo)致,如不合理的超時(shí)、重試設(shè)置導(dǎo)致的服務(wù)雪崩,流量突增導(dǎo)致的服務(wù)過載等,往往會(huì)將該服務(wù)集群直接壓垮。

當(dāng)多實(shí)例故障發(fā)生時(shí),故障面相對(duì)較大,可能在借助 Nginx 自動(dòng)健康檢查摘除的同時(shí),需要人工介入。

值得注意的是,Nginx 的健康檢查機(jī)制和 Proxy 重試一般是基于 Upstream 的延遲和 HTTP 狀態(tài)碼進(jìn)行判斷的。當(dāng) Upstream 節(jié)點(diǎn)宕機(jī)或進(jìn)程退出時(shí),Nginx 是很容易檢測(cè)并將其剔除。然后,現(xiàn)實(shí)情況并不總是這樣,之前的故障演練里也提到過,服務(wù)器節(jié)點(diǎn)可能會(huì)發(fā)生 CPU、存儲(chǔ)、磁盤、網(wǎng)絡(luò)的負(fù)載指標(biāo)不正常,對(duì)外的表現(xiàn)通常是耗時(shí)時(shí)高時(shí)低,很不穩(wěn)定,這種情況 Nginx 不一定能檢測(cè)和判斷準(zhǔn)確,往往會(huì)導(dǎo)致不能及時(shí)摘除,或者相反,導(dǎo)致誤判。

因此,一個(gè)高效、精準(zhǔn)的健康檢查機(jī)制至關(guān)重要,有條件的讀者可以嘗試自行研發(fā)一些組件,通過讀取監(jiān)控?cái)?shù)據(jù)來智能分析故障點(diǎn),并預(yù)測(cè)問題發(fā)生的時(shí)間和部位,實(shí)現(xiàn)自動(dòng) Failover。

1.3.4.中間件高可用

很多中間件都提供了原生的集群部署能力,如互聯(lián)網(wǎng)業(yè)務(wù)系統(tǒng)常見的面向 OLTP 的存儲(chǔ)系統(tǒng):MySQL、Redis、MongoDB、HBase、Couchbase、Cassandra、Elasticsearch 等;消息中間件如 RocketMQ、Kafka 等;分布式協(xié)調(diào)服務(wù)如 Chubby、Zookeeper 等。

這里討論的也是這種集群化架構(gòu)的冗余能力,如果讀者的生產(chǎn)系統(tǒng)中間件尚未具備多實(shí)例的集群部署,建議盡快對(duì)架構(gòu)進(jìn)行升級(jí)換代。

集群化的中間件天然消除了單實(shí)例問題,但這樣就能萬無一失、永保平安了么?顯然不是,我們來分析下常見的中間件故障點(diǎn)以及應(yīng)對(duì)措施。

以常見的存儲(chǔ)系統(tǒng)為例,通常有主從式(Master-Slave)和去中心化兩種拓?fù)浼軜?gòu)模式。如 MySQL(主從式)、Redis(3.0 版本以下或主從式)、MongoDB(復(fù)制集)、Zookeeper 就是采用經(jīng)典的主從式架構(gòu),而 Couchbase、Cassandra 這類 NoSQL 存儲(chǔ)則是采用無中心的架構(gòu)。

主從式架構(gòu):主從式集群通常以讀寫分離的方式為客戶端提供服務(wù),即所有應(yīng)用節(jié)點(diǎn)寫入 Master 節(jié)點(diǎn),多個(gè) Slave 組合并采用負(fù)載均衡(服務(wù)端代理或 DNS 域名)的方式分?jǐn)傋x請(qǐng)求。

當(dāng)主從式集群的 Master 實(shí)例發(fā)生故障時(shí)(如圖 1?3 中 11 所示),通常會(huì)由健康檢查組件自動(dòng)檢測(cè),執(zhí)行重新選舉,將集群的 Slave 節(jié)點(diǎn)提升為 Master。整個(gè)過程對(duì)客戶端透明,切換時(shí)間視具體數(shù)據(jù)量和網(wǎng)絡(luò)狀況而變化,當(dāng)數(shù)據(jù)量很小時(shí),客戶端幾乎無感知。

當(dāng) Slave 實(shí)例發(fā)生故障時(shí)(如圖 1?3 中 12 所示),處理流程相對(duì)簡單,只需要將故障節(jié)點(diǎn)從負(fù)載均衡摘除即可。

無中心架構(gòu):去中心話的架構(gòu)簡單高效,以 Cassandra 為例,任何節(jié)點(diǎn)均可支持讀寫以及請(qǐng)求轉(zhuǎn)發(fā),數(shù)據(jù)通過一致性哈希的方式進(jìn)行分片,并且在其他節(jié)點(diǎn)上保存副本,客戶端可隨意調(diào)整一致性級(jí)別(Consistency Level)來在讀寫性能、強(qiáng)弱一致性語義之間達(dá)到平衡。

當(dāng)節(jié)點(diǎn)發(fā)生故障時(shí)(如圖 3?3 中 13 所示),集群會(huì)自動(dòng)識(shí)別到故障節(jié)點(diǎn),并進(jìn)行摘除。數(shù)據(jù)會(huì)發(fā)生 Rehash,而客戶端也會(huì)執(zhí)行 Failover 操作,挑選其他健康的協(xié)調(diào)節(jié)點(diǎn),重新建立連接。

1.3.5.同城多中心

前面的章節(jié)重點(diǎn)介紹了實(shí)例級(jí)別、分組級(jí)別和集群級(jí)別的故障點(diǎn)以及冗余、故障轉(zhuǎn)移方法,并沒有提及機(jī)房級(jí)別故障。然而,機(jī)房級(jí)別故障確實(shí)是頻繁發(fā)生的問題,需要引起重視。

在實(shí)際生產(chǎn)環(huán)境中,尤其是需要保持 7*24 小時(shí)高可用的互聯(lián)網(wǎng)業(yè)務(wù),不可能只部署一個(gè)機(jī)房,而是采用“同城多中心”的方式,來消除機(jī)房級(jí)別的單點(diǎn)故障,如圖 3?3 所示,通過負(fù)載均衡和前置機(jī)轉(zhuǎn)發(fā),實(shí)現(xiàn)了南北流量及東西流量在多機(jī)房的調(diào)度和轉(zhuǎn)移。

一般來說,企業(yè)會(huì)在分布在各地理位置的數(shù)據(jù)中心建立多機(jī)房,如在華北數(shù)據(jù)中心建立 3 個(gè) IDC,依次編號(hào)為 HB-IDC-01、HB-IDC-02 和 HB-IDC-03。

還有一種數(shù)據(jù)中心的建設(shè)方式也比較常見,即遵循 Region-AZ-IDC 的設(shè)計(jì)模式,其中 Region 就是地理位置,如華北、華南。AZ(Available Zone)指可用區(qū),表示應(yīng)用的最小部署單元,通常由多個(gè) IDC 組成。

除非特別指定,本文通篇默認(rèn)會(huì)遵循“地理位置-數(shù)據(jù)中心-機(jī)房”的設(shè)計(jì)模式。

如圖 1?3 中 7 標(biāo)注所示,當(dāng) HB-IDC-03 出現(xiàn)故障時(shí),整個(gè)機(jī)房將不可用。這種情況時(shí)有發(fā)生,不可避免。原因也很復(fù)雜,可能是機(jī)房基礎(chǔ)設(shè)施故障(如電力系統(tǒng)問題、溫度、濕度失調(diào)),也可能是網(wǎng)絡(luò)故障(如核心交換機(jī)出錯(cuò)、網(wǎng)絡(luò)割接誤操作等)導(dǎo)致。

常見的故障轉(zhuǎn)移方式在故障預(yù)案中有提及過。接入層面,通過調(diào)整各級(jí)組件(DNS、SLB、Nginx 等),實(shí)現(xiàn)下一級(jí)接入層安全轉(zhuǎn)移;服務(wù)層面,通過調(diào)整接入層,對(duì)流量進(jìn)行重新調(diào)度,將故障機(jī)房的服務(wù)進(jìn)行隔離;中間件層面,通過集群的健康檢查機(jī)制,調(diào)整集群拓?fù)浜妥x寫方式。

1.3.6.兩地三中心

前面提到了機(jī)房級(jí)別的故障,實(shí)際中還會(huì)存在地域級(jí)別的故障,一般由自然災(zāi)害(暴雨、洪澇災(zāi)害、地震等)或骨干網(wǎng)中斷(如光纖被挖斷)導(dǎo)致。因此,對(duì)于規(guī)模較大、可靠性要求較高(尤其是金融級(jí)別)的業(yè)務(wù)系統(tǒng),靠一個(gè)地理位置數(shù)據(jù)中心來支撐流量顯然是不夠的。因此,很多公司從容災(zāi)的角度考慮,建立了“兩地三中心”機(jī)制。

所謂兩地三中心,是指在兩地建立三個(gè)數(shù)據(jù)中心,兩地之間通常需要保持 1000 公里以上的距離,避免距離太近導(dǎo)致兩地一起失效,反而起不到災(zāi)備效果。

以華北兩個(gè)數(shù)據(jù)中心,華南一個(gè)災(zāi)備中心來舉例說明。業(yè)務(wù)系統(tǒng)在華北兩個(gè)個(gè)數(shù)據(jù)中心正常提供服務(wù),而華南數(shù)據(jù)中心一般不提供服務(wù),偶爾也會(huì)提供少部分讀服務(wù)。生產(chǎn)環(huán)境產(chǎn)生的數(shù)據(jù),會(huì)異步復(fù)制到華南災(zāi)備中心。

當(dāng)華北的兩個(gè)數(shù)據(jù)中心出現(xiàn)重大故障時(shí),可以將用戶流量切換到華南災(zāi)備中心,由該數(shù)據(jù)中心接管線上業(yè)務(wù)請(qǐng)求。

正如故障轉(zhuǎn)移章節(jié)提到的,兩地三中心有一個(gè)很大的弊端,在于災(zāi)備中心通常是冷備角色,平時(shí)不會(huì)頻繁的進(jìn)行切換演練,或者幾乎就不會(huì)考慮演練。關(guān)鍵時(shí)刻可能就會(huì)由于各部件失效、或過載,導(dǎo)致沒法承接流量。另外一個(gè)問題就在于,冷備中心一般需要和兩個(gè)主數(shù)據(jù)中心的容量一致,但又不會(huì)提供活躍的服務(wù),這會(huì)導(dǎo)致嚴(yán)重的資源浪費(fèi)。

鑒于此,我們需要考慮異地多活的部署架構(gòu),下一章節(jié)會(huì)重點(diǎn)說明。?

1.3.7.異地多活

異地多活架構(gòu)可以說是高可用物理架構(gòu)中的終極形態(tài)。

大型的跨國公司(如 Google、Amazon、Microsoft)業(yè)務(wù)系統(tǒng)繁多且復(fù)雜度高,服務(wù)的用戶也會(huì)遍布全球,因此往往會(huì)在全球主要戰(zhàn)略位置建立多個(gè)數(shù)據(jù)中心。

圖 1?4 全球數(shù)據(jù)中心分布樣例

如圖 1?4 所示,是一個(gè)大規(guī)模的公有云服務(wù)(如 Amazon AWS,Microsoft Azure 等)在全球的數(shù)據(jù)中心分布:北美、南美、歐洲、亞太、澳洲、非洲等。

國內(nèi)的很多互聯(lián)網(wǎng)業(yè)務(wù)(如電商、社交、視頻、廣告、出行、本地服務(wù)等)也爭先恐后在全國各地建立了多個(gè)數(shù)據(jù)中心,常見的有:華北、華東、華南、華中等。

如此規(guī)模的異地多活物理架構(gòu)部署,挑戰(zhàn)性是毋庸置疑的。主要來自兩個(gè)方面:

1. 數(shù)據(jù)的復(fù)制延遲。跨地域的網(wǎng)絡(luò)情況不容樂觀,很容易發(fā)生延遲升高、丟包率升高。而數(shù)據(jù)在各個(gè)數(shù)據(jù)中心的復(fù)制也會(huì)隨之受到影響,數(shù)據(jù)不能高效及時(shí)的復(fù)制到目標(biāo)數(shù)據(jù)中心,就會(huì)導(dǎo)致用戶訪問的數(shù)據(jù)出現(xiàn)延遲和不一致,有時(shí)候用戶體驗(yàn)是不可接受的。

2. 一致性要求與寫沖突。某些業(yè)務(wù)要求的一致性較高,甚至是強(qiáng)一致,在跨地域復(fù)制的情況下幾乎是不可能實(shí)現(xiàn)的。另外,有些存儲(chǔ)系統(tǒng)如果設(shè)計(jì)成多點(diǎn)寫入的話,則會(huì)出現(xiàn)寫入沖突,如何解決沖突也是一個(gè)比較棘手的問題。

如圖 1?3 所示,通過 DNS 智能解析,將不同地理位置的用戶就近接入當(dāng)?shù)財(cái)?shù)據(jù)中心。在數(shù)據(jù)中心內(nèi)部,服務(wù)集群一定是本地部署的,而中間件集群則會(huì)根據(jù)不同的中間件特點(diǎn)而獨(dú)立設(shè)計(jì):

  • 一種設(shè)計(jì)模式,是單一中間件集群橫跨各數(shù)據(jù)中心,通常是類似于 MySQL 的 Master-Slave 架構(gòu)。寫入操作回流到 Master 節(jié)點(diǎn)所在數(shù)據(jù)中心執(zhí)行單點(diǎn)寫入,再讀取本地 Slave 節(jié)點(diǎn)以提升性能。這種方式比較常見,因?yàn)椴僮骱啽?#xff0c;缺點(diǎn)是寫入性能差,當(dāng)數(shù)據(jù)中心之間網(wǎng)絡(luò)發(fā)生分區(qū)后,寫入只得被迫中斷。另外會(huì)帶來數(shù)據(jù)復(fù)制延遲問題。
  • 另一種設(shè)計(jì)模式,也是單一中間件集群橫跨各數(shù)據(jù)中心,通常是類似于 Cassandra 的去中心化結(jié)構(gòu)。可以支持多點(diǎn)寫入,這樣讀、寫操作就可以在本地?cái)?shù)據(jù)中心完成。性能表現(xiàn)較好,但會(huì)帶來數(shù)據(jù)復(fù)制延遲和沖突修復(fù)的問題。
  • 還有一種設(shè)計(jì)模式,是在每個(gè)數(shù)據(jù)中心部署獨(dú)立的集群,本地直接執(zhí)行讀、寫操作,中間件集群之間跨地域復(fù)制數(shù)據(jù)。性能也比較好,但同樣會(huì)帶來數(shù)據(jù)復(fù)制延遲和沖突修復(fù)的問題。

不難看出,無狀態(tài)的服務(wù)在異地多活架構(gòu)中可以做到游刃有余,只需要調(diào)度流量即可。但數(shù)據(jù)層面卻成了阻礙多活架構(gòu)的核心焦點(diǎn)。為了解決以上問題,很多公司嘗試了 Sharding 化部署的思想,比如阿里的單元化架構(gòu)設(shè)計(jì)。

Sharding 化部署的核心思路,在于將用戶流量集中在一個(gè)數(shù)據(jù)中心完成,完成交易的封閉處理,即同一個(gè)事務(wù)請(qǐng)求處理以及對(duì)應(yīng)的數(shù)據(jù),不應(yīng)該跨數(shù)據(jù)中心。

常見的設(shè)計(jì)方案就是選擇 Sharding Key(比如用戶 ID),在接入層將請(qǐng)求會(huì)話路由和粘滯到對(duì)應(yīng)的機(jī)房單元。數(shù)據(jù)層面也是根據(jù)該 Sharding Key 進(jìn)行路由讀寫。路由算法是穩(wěn)定的,因此無論該用戶發(fā)起多少次請(qǐng)求,處理流程和對(duì)應(yīng)數(shù)據(jù)都一定會(huì)進(jìn)入對(duì)應(yīng)的部署單元處理,不會(huì)出現(xiàn)由于跨單元而出現(xiàn)數(shù)據(jù)不一致的問題。

仔細(xì)思考一下,這種 Sharding 化部署真的無懈可擊嗎?不一定!最常見的問題就是維度的變化使得讀寫必須要橫跨數(shù)據(jù)中心。以電商業(yè)務(wù)為例來說明,假設(shè)存在買家、賣家和商品維度,當(dāng)前選取的 Sharding Key 為買家 ID,也就是說同一買家的任意請(qǐng)求都會(huì)落到同一數(shù)據(jù)中心來處理,包括產(chǎn)生的數(shù)據(jù)也會(huì)落到該中心的存儲(chǔ)系統(tǒng)中。

如果買家下單后,同時(shí)要求減少商品庫存,如果庫存不足還要對(duì)該商品進(jìn)行下架。另外,還需要給買家增加信譽(yù)度積分。如果以上這些操作要求是強(qiáng)一致的,即下單后需要馬上看到庫存變化和賣家積分變化在頁面上同步顯示,這種場景通過 Sharding 化的多活架構(gòu)就沒法實(shí)現(xiàn)。當(dāng)然,如果可以接受最終一致,則可以通過消息中間件,將數(shù)據(jù)變化同步到其他的數(shù)據(jù)中心,頁面經(jīng)過一段延遲后即可顯示變化。

顯然,異地多活是沒有銀彈的,很難做到高性能、強(qiáng)一致性和高可用性都能同時(shí)得到滿足,這和 CAP 的原理也很相似。?

1.3.8.容易忽視的 Worker 高可用

Worker 類組件是微服務(wù)架構(gòu)中不可或缺的一部分,但其高可用卻最容易被忽視,因?yàn)檫@一類組件往往默默無聞在背后工作,卻又擔(dān)任著重要的角色,一旦失效,可能報(bào)表就無法生成,數(shù)據(jù)預(yù)處理就會(huì)失敗,緩存預(yù)加載的數(shù)據(jù)就會(huì)丟失。

Worker 類的高可用關(guān)鍵在于“監(jiān)視”和冗余部署,當(dāng)有合適的 HA 監(jiān)視組件發(fā)現(xiàn) Worker 不工作或狀態(tài)不健康,并能及時(shí)執(zhí)行 Failover,則問題就可以迎刃而解。

有一類 Worker 通常是消息中間件的消費(fèi)者(Consumer),由于消息中間件天然具備消息投遞的負(fù)載均衡和節(jié)點(diǎn)發(fā)現(xiàn)能力,所以這類 Worker 應(yīng)用也就很容易具備高可用特性。當(dāng)出現(xiàn)消費(fèi)節(jié)點(diǎn)宕機(jī)或消費(fèi)緩慢問題,消息中間件會(huì)自動(dòng)停止消息投遞。

而大部分自研的 Worker 類應(yīng)用,由于不存在 HA 監(jiān)控,再加上系統(tǒng)往往以單實(shí)例的方式部署,因此不具備任何高可用。我們可以設(shè)計(jì)一套分布式的架構(gòu),提升系統(tǒng)可用性,如圖 1?5 所示。

圖 1?5 一種高可用的分布式 Worker 設(shè)計(jì)

以 Zookeeper 為協(xié)調(diào)中心,設(shè)置 Leader 和多個(gè) Follower 節(jié)點(diǎn)。其中,Leader 節(jié)點(diǎn)接受來自控制平面(Control Plane)的任務(wù)分配和一系列控制指令,而 Follower 節(jié)點(diǎn)則會(huì)執(zhí)行 Leader 分配的任務(wù)。Follower 可以設(shè)計(jì)成 Active-Active 模式或 Active-Passive 模式。

當(dāng) Leader 或 Follower 節(jié)點(diǎn)宕機(jī)時(shí),會(huì)觸發(fā) Zookeeper 的 ephemeral znode 感知到事件并通知所有節(jié)點(diǎn),從而觸發(fā)一次新的選舉或任務(wù) Rebalance,這些操作可以利用一些 high-level 的組件如 curator 來輔助實(shí)現(xiàn),無需從底層開發(fā)。

1.4.超時(shí)

無數(shù)慘痛的生產(chǎn)環(huán)境事故和經(jīng)驗(yàn)教訓(xùn)表明,不正確的超時(shí)設(shè)置是造成微服務(wù)級(jí)聯(lián)故障和雪崩的頭號(hào)殺手。遺憾的是,大量的工程師完全沒有意識(shí)到這一點(diǎn),每年都有大量的線上服務(wù)在超時(shí)方面反復(fù)栽跟頭。

本章節(jié)就來聊一聊超時(shí)的問題、預(yù)防措施和經(jīng)驗(yàn)總結(jié)。

1.4.1.超時(shí)與雪崩

微服務(wù)的分布式特性,使得服務(wù)之間的調(diào)用和互操作極其頻繁,隨著業(yè)務(wù)的拓展,服務(wù)間調(diào)用管用關(guān)系也會(huì)變得錯(cuò)綜復(fù)雜,如圖 1?6 所示。

圖 1?6 微服務(wù)間調(diào)用關(guān)系

如果服務(wù)間調(diào)用未設(shè)置超時(shí),或超時(shí)設(shè)置不合理,則會(huì)帶來級(jí)聯(lián)故障風(fēng)險(xiǎn)。當(dāng)某一系統(tǒng)發(fā)生故障時(shí),服務(wù)不可用,上游就會(huì)出現(xiàn)調(diào)用延遲升高。如果沒有合理的超時(shí)參數(shù)控制,則故障就會(huì)順著調(diào)用鏈級(jí)聯(lián)傳播,最終導(dǎo)致關(guān)鍵路徑甚至所有服務(wù)不可用,如圖 1?7 所示。

圖 1?7 由微服務(wù) G 故障導(dǎo)致的大部分服務(wù)不可用

這種級(jí)聯(lián)故障現(xiàn)象也稱為“雪崩”,雪崩帶來的影響不僅僅是響應(yīng)慢,更嚴(yán)重的是會(huì)耗盡系統(tǒng)資源,使得整個(gè)系統(tǒng)完全癱瘓。

以基于 Spring Boot 開發(fā)的微服務(wù)為例,默認(rèn)的 Tomcat 連接池大小為 200,也就是說默認(rèn)單實(shí)例只允許同時(shí)存在 200 個(gè)并發(fā)請(qǐng)求。這在平時(shí)是毫無壓力的,但雪崩發(fā)生時(shí),所有的請(qǐng)求就會(huì)一直在等待,連接池迅速就被占滿,從而導(dǎo)致其他請(qǐng)求無法進(jìn)入,系統(tǒng)直接癱瘓。

要想解決雪崩問題,就必須設(shè)置合理的超時(shí)參數(shù)。以 Java 應(yīng)用來說,常見的超時(shí)設(shè)置主要有 HttpClient 和各類中間件系統(tǒng),尤其是數(shù)據(jù)庫、緩存。一般來說,服務(wù)間調(diào)用超時(shí)和數(shù)據(jù)庫訪問,建議設(shè)置超時(shí)時(shí)間不超過 500ms,緩存類超時(shí)時(shí)間不超過 200ms。

1.4.2.警惕不合理的連接池超時(shí)設(shè)置

有一類超時(shí)問題比較隱蔽而且風(fēng)險(xiǎn)很高,缺乏經(jīng)驗(yàn)的工程師很難發(fā)現(xiàn)。以 HttpClient 連接池來說,通常大部分人都正確設(shè)置了創(chuàng)建連接超時(shí)(ConnectTimeout)和讀取超時(shí)(SocketTimeout),但卻忽略了連接池獲取連接超時(shí)(ConnectionRequestTimeout)的設(shè)置。

當(dāng)目標(biāo)服務(wù)超時(shí)發(fā)生,有時(shí)候會(huì)發(fā)現(xiàn)盡管設(shè)置了讀取超時(shí),系統(tǒng)還是會(huì)出現(xiàn)雪崩。原因就是連接池獲取連接默認(rèn)是無限等待,這就導(dǎo)致了當(dāng)前請(qǐng)求被掛起,直到系統(tǒng)資源被耗盡。這里給出一種實(shí)際生產(chǎn)環(huán)境使用的配置。

RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(500).setSocketTimeout(500).setConnectTimeout(500).build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();cm.setMaxTotal(maxTotal);// 整個(gè)連接池最大連接數(shù)cm.setDefaultMaxPerRoute(maxPerRoute);// 每路由最大連接數(shù),默認(rèn)值是2cm.closeExpiredConnections();cm.closeIdleConnections(200, TimeUnit.MILLISECONDS);CloseableHttpClient httpClient =HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).setKeepAliveStrategy(new ConsutomConnectionKeepAliveStrategy(30000L)).disableAutomaticRetries().setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)).build();

復(fù)制

當(dāng)發(fā)生讀取超時(shí)的時(shí)候,當(dāng)前路由的并發(fā)連接數(shù)迅速被占滿,無連接可用。新的業(yè)務(wù)請(qǐng)求在等待 500ms 后就會(huì)退出請(qǐng)求,從而有效保護(hù)了服務(wù)不被堆積的請(qǐng)求壓垮。

1.4.3.動(dòng)態(tài)超時(shí)與自適應(yīng)超時(shí)

實(shí)際場景中,如果對(duì)所有的服務(wù)調(diào)用超時(shí)都搞“一刀切”,比如都設(shè)置為 500ms,則會(huì)過于死板,缺乏靈活性。比如有些服務(wù)調(diào)用量并不高,但是延遲偏高,而有些服務(wù)性能高,TP99 可能才不到 100ms,服務(wù)提供方也能承諾服務(wù)的性能可以長期得到保證。

這種情況就可以考慮動(dòng)態(tài)超時(shí)和自適應(yīng)超時(shí)方案。

所謂動(dòng)態(tài)超時(shí),是指可以通過控制后臺(tái),人為在運(yùn)行時(shí)干預(yù)超時(shí)參數(shù)。還是以 HttpClient 為例說明,可以通過配置中心,針對(duì)某些 API URL 動(dòng)態(tài)調(diào)整參數(shù),代碼樣例如下:

// 配置中心控制接口超時(shí)HttpClientInterceptor.setupRequestConfigIfNeeded(request); public static void setupRequestConfigIfNeeded(HttpRequestBase requestBase) { if (isDynamicTimeoutEnabled()) { String key = getKey(requestBase, HTTP_CLIENT_APPLICATION); TimeoutHolder timeout = HTTP_CLIENT_TIMEOUT_CACHE.get(key); if (timeout != null) { RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout( timeout.getConnectionRequestTimeout()).setConnectTimeout( timeout.getConnectTimeout()).setSocketTimeout(timeout.getSocketTimeout()).build(); requestBase.setConfig(requestConfig); } }} private static boolean isDynamicTimeoutEnabled() { String dynamicTimeoutEnabled = getStringConfig(NS_HTTP_CLIENT_TIMEOUT, HTTP_CLIENT_SWITCH, "false"); return "true".equals(dynamicTimeoutEnabled);}

復(fù)制

所謂自適應(yīng)超時(shí),本質(zhì)上是一種自動(dòng)化的動(dòng)態(tài)超時(shí)。可以在服務(wù)調(diào)用方實(shí)時(shí)監(jiān)控目標(biāo)服務(wù)的調(diào)用 QPS、耗時(shí)和錯(cuò)誤率,當(dāng)檢測(cè)到耗時(shí)較低,則可以預(yù)測(cè)后續(xù)的耗時(shí)情況并調(diào)整參數(shù)配置。如果出現(xiàn)大量的超時(shí),自適應(yīng)控制也可以將超時(shí)閾值進(jìn)一步調(diào)低,避免調(diào)用鏈路上耗時(shí)升高帶來不必要的損失。

1.4.4.超時(shí)的套娃原則

理想情況下,超時(shí)的參數(shù)配置應(yīng)該是遵循“套娃原則”,即沿著調(diào)用鏈,超時(shí)的閾值設(shè)定應(yīng)該是逐級(jí)減小的。

如果超時(shí)是逐級(jí)增大的,則會(huì)出現(xiàn):在上游已超時(shí)返回的情況下,下游還在繼續(xù)處理,造成不必要的資源浪費(fèi)。如果反過來,上游還在等待,下游可能已超時(shí)并進(jìn)行再次重試,這樣當(dāng)前請(qǐng)求的成功率就會(huì)得到提升。

1.5.重試

重試是一把雙刃劍,既是提升服務(wù)間調(diào)用成功率、容錯(cuò)的一種重要手段,也是造成流量放大、服務(wù)過載的原因之一。

1.5.1.為什么要重試

當(dāng)微服務(wù)系統(tǒng)功能無法正常工作,或遠(yuǎn)程調(diào)用失敗時(shí),往往需要重試機(jī)制,在有限的時(shí)間段內(nèi)來提升調(diào)用成功率。

服務(wù)調(diào)用的重試與否,需要看場景,如果對(duì)業(yè)務(wù)處理的成功率要求很高且目標(biāo)服務(wù)可以承諾冪等性,可以增加重試。重試必須具備上限,不可以執(zhí)行無限制的、反復(fù)的嘗試。

重試的位置無處不在,既可以是來自客戶端的用戶手動(dòng)重試,也可以是服務(wù)端各組件之間的自動(dòng)重試。

當(dāng)客戶端出現(xiàn)全部或局部頁面加載失敗時(shí),可以通過友好的文字、圖片等方式來引導(dǎo)用戶手動(dòng)重試加載,如提示語“網(wǎng)絡(luò)似乎開了點(diǎn)小差,請(qǐng)?jiān)俅沃卦嚒薄?/p>

在服務(wù)端,接入層也可以增加重試能力,常見的就是 Nginx 的代理重試。如以下配置:

#重試設(shè)置proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_504 | off; //出現(xiàn)哪些情況,會(huì)請(qǐng)求其他后端服務(wù)器重試,off則不重試;proxy_next_upstream_timeout 10s; //即proxy_next_upstream_timeout時(shí)間內(nèi)允許嘗試proxy_next_upstream_tries次;proxy_next_upstream_tries 2; //

復(fù)制

而應(yīng)用層重試一般指 HTTP API 調(diào)用或 RPC 服務(wù)調(diào)用的重試設(shè)置,也包括各種中間件 SDK 自帶的原生重試能力。

1.5.2.重試風(fēng)暴

毋容置疑,重試會(huì)放大請(qǐng)求量。重試觸發(fā)的條件一般是目標(biāo)服務(wù)或中間件系統(tǒng)出現(xiàn)了不健康狀態(tài)或不可用,在這種情況下,無論是來自客戶端的用戶重試或來自服務(wù)的組件間的重試,都會(huì)引起“讀放大”效應(yīng)。這會(huì)給原本就處于故障狀態(tài)的組件雪上加霜,極端情況下會(huì)導(dǎo)致系統(tǒng)直接奔潰。

我們把這種由于大量重試導(dǎo)致的瞬間流量放大造成的類似 DDoS 攻擊效應(yīng),稱為“重試風(fēng)暴”。重試風(fēng)暴是造成系統(tǒng)過載和奔潰的重要原因,需要努力避免。

1.5.3.退避原則

為了減少重試風(fēng)暴帶來的危害,一種行之有效的方法是增加重試的時(shí)間間隔,通過退避(back-off)的方法來逐步增加等待時(shí)間。最常見的做法是指數(shù)退避(exponential back-off)原則。

舉個(gè)例子,設(shè)置初始重試等待時(shí)間為 10ms,重試上限為 5 次。當(dāng)目標(biāo)系統(tǒng)出現(xiàn)故障時(shí),調(diào)用方等待 10ms 后發(fā)起重試,如果請(qǐng)求依舊失敗,則客戶端等待 20ms 后再次發(fā)起重試。如果再次請(qǐng)求失敗,則等待 40ms 后再次重試,以此類推,直到返回正確的結(jié)果或達(dá)到重試上限。

1.5.4.指數(shù)退避的風(fēng)險(xiǎn)

指數(shù)退避的特性會(huì)使得重試間隔時(shí)間按指數(shù)級(jí)別遞增,在極端情況下,會(huì)導(dǎo)致單次請(qǐng)求的耗時(shí)被嚴(yán)重放大,從而導(dǎo)致系統(tǒng)資源被耗盡,進(jìn)一步拖垮系統(tǒng)。需要引起格外注意。

建議減少初始等待時(shí)間,并且嚴(yán)格限制重試次數(shù)上限,比如只重試一次。

1.5.5.動(dòng)態(tài)重試

為了兼顧重試帶來成功率提升的收益,以及減少重試風(fēng)暴帶來的流量放大和耗時(shí)提升。我們可以考慮采用動(dòng)態(tài)重試方案來進(jìn)一步提升系統(tǒng)的靈活性。

通過在服務(wù)調(diào)用方預(yù)先植入動(dòng)態(tài)開關(guān)邏輯,可以在運(yùn)行時(shí)動(dòng)態(tài)調(diào)整重試參數(shù)。包括:

  • 開啟和停止重試功能;
  • 調(diào)整重試次數(shù)上限;
  • 調(diào)整重試模式,是普通的重試操作,還是指數(shù)退避重試;
  • 如果是指數(shù)退避,可以調(diào)整初始重試間隔時(shí)間;

以上操作既可以是全局操作,也可以按系統(tǒng)、或目標(biāo)服務(wù)的顆粒度進(jìn)行操作。

1.6.限流

限流是保護(hù)業(yè)務(wù)系統(tǒng)的必不可少的環(huán)節(jié)。當(dāng)流量突增時(shí),一個(gè)擁有良好限流設(shè)計(jì)的系統(tǒng)能夠抗住流量,快速丟棄多余的請(qǐng)求,讓內(nèi)部的微服務(wù)系統(tǒng)不受影響。

限流是一種有損的可靠性方案,限流生效時(shí),有部分用戶是無法正常加載頁面的。同一用戶也可能會(huì)出現(xiàn)正常訪問和被限流交替發(fā)生。盡管如此,限流仍是抵御突發(fā)流量的不二法門,有損的服務(wù)一定勝過服務(wù)被全量壓垮。

1.6.1.限流的位置與粒度

和超時(shí)、重試一樣,限流的位置也是遍布到微服務(wù)的各組件,甚至是客戶端應(yīng)用。通常離用戶越近的位置,限流效果越明顯。

常見的限流位置有客戶端限流、接入層限流和服務(wù)層限流。客戶端可以對(duì)單一用戶的操進(jìn)行限流,避免用戶反復(fù)重試,比如可以在用戶下單后,將按鈕置灰,防止用戶多次重試。接入層限流是服務(wù)端最有效的位置,可以通過令牌桶或漏桶算法,對(duì)遠(yuǎn)程 IP 進(jìn)行限流,或?qū)ο掠畏?wù)進(jìn)行限流。應(yīng)用層限流一般為單機(jī)限流,具體限流閾值通常以單機(jī)壓測(cè)的結(jié)果為基準(zhǔn)進(jìn)行估算。

限流的粒度可以是全局限流,也可以是服務(wù)粒度,或者是 API 根目錄,甚至可以設(shè)置為特定的 API URL。這些粒度應(yīng)該可以支持在控制后臺(tái)動(dòng)態(tài)配置。

1.6.2.主動(dòng)限流與被動(dòng)限流

所謂主動(dòng)限流,是指服務(wù)的提供方主動(dòng)評(píng)估服務(wù)的容量和峰值 QPS,提前配置限流閾值并說明限流后的服務(wù)表現(xiàn)。服務(wù)的使用方無需關(guān)心這些服務(wù)的性能和可靠性,只需要按照限流的標(biāo)準(zhǔn)進(jìn)行容錯(cuò)處理即可。這種方式是一種比較友好的合作模式。

被動(dòng)限流則恰恰相反,服務(wù)的提供方無法了解和評(píng)估自身的服務(wù)狀態(tài),上游流量突增后也不具備技術(shù)手段來應(yīng)對(duì)。這種情況可以考慮服務(wù)調(diào)用方實(shí)施被動(dòng)限流,即對(duì)服務(wù)的使用方、各種存儲(chǔ)、中間件等資源增加限流約束機(jī)制,理想情況應(yīng)該可以支持控制后臺(tái)隨時(shí)調(diào)整。

1.6.3.警惕泄洪流量

有一種情況很容易被忽略,當(dāng)一組消費(fèi)者(Consumer)同時(shí)處理來自消息中間件的消息時(shí),往往由于某些內(nèi)部組件的延遲(如寫入存儲(chǔ)緩慢、第三方服務(wù)延遲升高等)或上游消息量突增導(dǎo)致消息積壓,一般會(huì)修復(fù)慢的組件或增加更多的消費(fèi)者來解決這些問題。當(dāng)這些瓶頸解除后,消費(fèi)者的處理速度會(huì)大幅提升,瞬間積壓的消息會(huì)被大量處理,從而導(dǎo)致下游系統(tǒng)出現(xiàn)過載現(xiàn)象,或出現(xiàn)主從數(shù)據(jù)同步出現(xiàn)大量的滯后(Lag)。我們姑且稱這種流量為“泄洪流量”。

泄洪流量在真實(shí)場景中經(jīng)常會(huì)發(fā)生,而且會(huì)帶來嚴(yán)重的影響,因?yàn)楹芏嘞到y(tǒng)的設(shè)計(jì)(如 CQRS 架構(gòu)風(fēng)格)出于資源限制、或架構(gòu)的簡潔性考慮,往往會(huì)讓這些消費(fèi)者和線上服務(wù)共享存儲(chǔ)資源(尤其是寫庫)或調(diào)用公共服務(wù)。當(dāng)泄洪流量發(fā)生時(shí),這些存儲(chǔ)資源可能就會(huì)出現(xiàn)負(fù)載極速上升、主從數(shù)據(jù)同步 Lag 被拉大,公共服務(wù)甚至可能會(huì)被立刻打垮。

解決方案其實(shí)很簡單,消費(fèi)者的應(yīng)用集群也應(yīng)該和在線服務(wù)一樣,設(shè)置限流機(jī)制。

1.7.降級(jí)熔斷

降級(jí)、熔斷是另外一種保護(hù)手段,這是一種“棄卒保車”的制勝策略。當(dāng)局部系統(tǒng)或組件不可靠時(shí),通過對(duì)該故障域進(jìn)行降級(jí)、熔斷處理,并展示有損的降級(jí)數(shù)據(jù),從而達(dá)到快速隔離故障的目的,且用戶體驗(yàn)犧牲不明顯。降級(jí)熔斷的關(guān)鍵在于識(shí)別問題和降級(jí)策略。

1.7.1.降級(jí)的位置與粒度

和限流很相似,降級(jí)的位置也是越多越好,降級(jí)層次越多,系統(tǒng)就越靈活可控。通常可降級(jí)的位置有客戶端、接入層和應(yīng)用層。

客戶端降級(jí)可以有效抵御大量的無效請(qǐng)求入侵服務(wù)端系統(tǒng)。當(dāng)客戶端識(shí)別到后端服務(wù)工作在不健康狀態(tài)時(shí),可以執(zhí)行本地降級(jí),屏蔽一些操作(如評(píng)論加載),并且將預(yù)先埋入的提示語展示給用戶,如“評(píng)論似乎開了一點(diǎn)小差,請(qǐng)稍后再試”。

當(dāng)接入層檢測(cè)到 Upstream 層服務(wù)有故障時(shí),如延遲升高、響應(yīng)狀態(tài)碼不符合預(yù)期等,可以對(duì)該服務(wù)請(qǐng)求執(zhí)行“快速失敗”處理,向請(qǐng)求方輸出錯(cuò)誤提示,或輸出預(yù)先緩存的退化數(shù)據(jù)。

應(yīng)用層的降級(jí)相對(duì)更靈活,可以設(shè)置很多降級(jí)策略,如基于請(qǐng)求 QPS、請(qǐng)求的長尾延遲、超時(shí)率或錯(cuò)誤率等,并且可以提前根據(jù)不同策略處理好降級(jí)數(shù)據(jù)。

降級(jí)的粒度可以是全局限流,也可以是服務(wù)粒度,或者是 API 根目錄,甚至可以設(shè)置為特定的 API URL。這些粒度應(yīng)該可以支持在控制后臺(tái)動(dòng)態(tài)配置。

1.7.2.主動(dòng)降級(jí)與被動(dòng)降級(jí)

主動(dòng)降級(jí)是指直接將對(duì)外提供的服務(wù)(如 RESTful API)降級(jí)掉,輸出降級(jí)錯(cuò)誤提示,或一組緩存的業(yè)務(wù)數(shù)據(jù),這些數(shù)據(jù)通常不是那么及時(shí),甚至是“臟”數(shù)據(jù)。主動(dòng)降級(jí)是一種粗粒度的降級(jí)。

被動(dòng)降級(jí)是指將不健康的第三方服務(wù)或組件降級(jí),這通常是一種細(xì)粒度的降級(jí)策略。降級(jí)的結(jié)果就是當(dāng)前調(diào)用無法返回?cái)?shù)據(jù),或者返回緩存的舊數(shù)據(jù),基于這些降級(jí)數(shù)據(jù),服務(wù)端再處理本次請(qǐng)求事務(wù)。

1.7.3.強(qiáng)弱依賴

微服務(wù)架構(gòu)的依賴非常多,比如服務(wù)間調(diào)用(HTTP/RPC)、數(shù)據(jù)庫讀取、緩存訪問、消息中間件訂閱與消費(fèi)等等,這些依賴項(xiàng)構(gòu)成了微服務(wù)系統(tǒng)的拓?fù)浣Y(jié)構(gòu)。

根據(jù)業(yè)務(wù)的不同,有些依賴是必不可少的,當(dāng)出現(xiàn)故障時(shí),整個(gè)大系統(tǒng)就面臨著不可用的風(fēng)險(xiǎn),我們把這種依賴稱為“強(qiáng)依賴”。比如 Feed 業(yè)務(wù)中的推薦服務(wù),就是一種典型的強(qiáng)依賴,當(dāng)推薦服務(wù)不可用,整個(gè) Feed 流就面臨著無數(shù)據(jù)可用的困境。

有些依賴項(xiàng)在出現(xiàn)故障時(shí),可以丟棄,業(yè)務(wù)上不會(huì)產(chǎn)生明顯的影響,我們稱之為“弱依賴”。比如在 Feed 業(yè)務(wù)中的用戶服務(wù)和緩存,當(dāng)出現(xiàn)問題時(shí),完全可以拋棄,對(duì)用戶的影響就是每條 Feed 的作者頭像和昵稱丟失,業(yè)務(wù)層面一般可以接受。

微服務(wù)架構(gòu)設(shè)計(jì)的一個(gè)重要準(zhǔn)則就是一切盡可能弱依賴,解除強(qiáng)依賴。這意味著在代碼開發(fā)階段,需要面向失敗設(shè)計(jì),做好依賴項(xiàng)失敗的降級(jí)處理。

1.7.4.降級(jí)數(shù)據(jù)

降級(jí)就意味著丟棄弱依賴、解除強(qiáng)依賴,意味著需要輸出退化的降級(jí)數(shù)據(jù)給調(diào)用方,降級(jí)數(shù)據(jù)的準(zhǔn)備是有技巧的。我們來分析下常見降級(jí)數(shù)據(jù)和請(qǐng)求的關(guān)系:

  • 降級(jí)數(shù)據(jù)和用戶無相關(guān),如商品的基本信息,并不會(huì)隨著用戶的不同而發(fā)生變化;
  • 降級(jí)數(shù)據(jù)和用戶強(qiáng)相關(guān),如訂單列表、購物車等,不同用戶的數(shù)據(jù)完全不一樣;
  • 降級(jí)數(shù)據(jù)和用戶弱相關(guān),如視頻播放,視頻的基本播放屬性不隨用戶變化,但鑒權(quán)部分會(huì)隨著免費(fèi)、付費(fèi)用戶的不同而存在區(qū)別;

好的,有了這三種降級(jí)數(shù)據(jù)類型,我們就可以有針對(duì)的去準(zhǔn)備數(shù)據(jù)。

一種建議的方案就是在正常讀取依賴數(shù)據(jù)后,異步寫入降級(jí)存儲(chǔ)系統(tǒng),這個(gè)存儲(chǔ)一般由大存儲(chǔ)量的 NoSQL 數(shù)據(jù)庫來承擔(dān)即可,可以有效提升降級(jí)數(shù)據(jù)的寫入和讀取效率。對(duì)于用戶無相關(guān)的數(shù)據(jù),可以設(shè)置維度 Key,如 fallback_product_<pid>標(biāo)識(shí)了某商品的 Key,并將數(shù)據(jù)以 Value 的形式寫入存儲(chǔ);對(duì)于用戶強(qiáng)相關(guān)和弱相關(guān)的數(shù)據(jù),Key 需要增加用戶維度,如 fallback_order_<orderid>_uid_<uid>表示某用戶的訂單數(shù)據(jù)。

1.7.5.熔斷

從某種意義上來說,超時(shí)和限流可以認(rèn)為是一種低級(jí)形態(tài)的降級(jí)策略,而熔斷則是一種高級(jí)形態(tài)的降級(jí)。

熔斷器設(shè)計(jì)模式是一種很經(jīng)典的彈性容錯(cuò)算法,如圖 1?8 所示。當(dāng)檢測(cè)到系統(tǒng)指標(biāo)出現(xiàn)異常并且達(dá)到一定的閾值后,熔斷器就會(huì)自動(dòng)打開,從而切斷對(duì)依賴性的調(diào)用,然后可以根據(jù)策略選擇一份降級(jí)數(shù)據(jù)。當(dāng)?shù)却龝r(shí)間超過預(yù)設(shè)的門檻值后,熔斷器會(huì)嘗試半關(guān)閉狀態(tài),部分請(qǐng)求開始調(diào)用真實(shí)的依賴項(xiàng),當(dāng)結(jié)果符合成功率標(biāo)準(zhǔn)時(shí),熔斷器會(huì)關(guān)閉,反之則熔斷器再次打開,依次類推。

熔斷器的好處是顯而易見的,使用熔斷器可以在問題累計(jì)到一定的程度后,直接斷開依賴、快速失敗,從而有效保護(hù)系統(tǒng)本身和依賴方,避免全量系統(tǒng)發(fā)生雪崩。

圖 1?8 微服務(wù)熔斷器設(shè)計(jì)模式

常見的開源熔斷器實(shí)現(xiàn)有 Hystrix 及其后繼者 Resillence4j、Sentinel 等。感興趣的讀者可以自行閱讀和調(diào)研官方文檔,并評(píng)估是否可以應(yīng)用到自身微服務(wù)項(xiàng)目中。

使用熔斷器需要注意幾個(gè)問題:

  • 有些熔斷器組件是代碼高侵入的,但粒度細(xì)、可控性強(qiáng),實(shí)際使用時(shí)需要在靈活性和代碼可維護(hù)性方面仔細(xì)權(quán)衡利弊;
  • 使用熔斷器是有額外性能開銷(Overhead)的,比如 Hystrix 的線程池隔離模式,會(huì)按需創(chuàng)建一個(gè)或多個(gè)線程池,這些線程會(huì)占用更多的 CPU 和內(nèi)存。有條件的讀者完全可以自行設(shè)計(jì)輕量級(jí)的熔斷器;
  • 一定要根據(jù)實(shí)際情況尤其是壓測(cè)指標(biāo),設(shè)置好門檻值(Threshold),避免狀態(tài)發(fā)生誤判,造成不必要的線上故障;

1.8.過載

流量的過載是影響系統(tǒng)可靠性、導(dǎo)致服務(wù)不可用的的一個(gè)重要因素。筆者曾經(jīng)經(jīng)歷過由于代碼缺陷導(dǎo)致的流量被放大到 9 倍,服務(wù)器和存儲(chǔ)系統(tǒng)的資源(CPU、內(nèi)存、網(wǎng)絡(luò)帶寬、磁盤 I/O)在不到 5 分鐘的時(shí)間內(nèi)就迅速消耗殆盡,系統(tǒng)無法正常提供對(duì)外服務(wù),幾乎所有業(yè)務(wù)系統(tǒng)都未能幸免,其結(jié)果是災(zāi)難性的。

本章節(jié)來分析下過載的原因以及解決方案。

1.8.1.過載的原因

過載的根本原因是流量發(fā)生突增,但系統(tǒng)資源承載能力不足。這里的資源包括但不限于:CPU 計(jì)算能力、內(nèi)存大小、外存(磁盤、SSD 等)容量、設(shè)備 I/O 速度、網(wǎng)絡(luò)帶寬、實(shí)例個(gè)數(shù)、中間件處理能力、第三方服務(wù)吞吐率,等等。

流量突增甚至在極端情況下可以產(chǎn)生脈沖流量。脈沖流量是指瞬間發(fā)生的超高流量,超出了日常流量峰值的好幾倍甚至是幾十、幾百倍。流量突增的原因通常包括:

  • DDoS 攻擊,尤其是來自于不同地理位置的僵尸網(wǎng)絡(luò);
  • 由于部分系統(tǒng)不可用,造成級(jí)聯(lián)故障傳導(dǎo),導(dǎo)致從客戶端到服務(wù)端內(nèi)部全鏈路上的大量重試,引起的重試風(fēng)暴;
  • 由于促銷、秒殺、Push 推送或運(yùn)營活動(dòng)導(dǎo)致的短時(shí)間用戶請(qǐng)求大量涌入;

內(nèi)部系統(tǒng)承載能力不足可能來自兩方面:

  • 容量已不能滿足日益增長的業(yè)務(wù)需求;
  • 由于故障轉(zhuǎn)移導(dǎo)致的臨時(shí)資源不足。這種情況非常常見,鑒于此,很多系統(tǒng)都會(huì)設(shè)計(jì)成 N+1 甚至 N+2 冗余度;

1.8.2.過載解決方案

過載的解決方案包括兩個(gè)基本原則:減少流量滲透和增加內(nèi)部系統(tǒng)承載能力。

所謂減少流量滲透,是指丟棄不必要的流量。常見的做法就是限流操作,針對(duì)不健康、異常的流量(如 DDoS)在接入層進(jìn)行清洗和過濾;針對(duì)其他突增的流量,如運(yùn)營活動(dòng)、Push 推送或重試導(dǎo)致的請(qǐng)求,通過限流組件來丟棄多余流量,確保傳導(dǎo)到下游的流量符合預(yù)期。限流要盡可能靠近調(diào)用鏈路的頭部,越靠前效果越佳。

另外,由于重試是造成流量突增的重要原因,我們應(yīng)該增加系統(tǒng)的動(dòng)態(tài)重試能力,當(dāng)出現(xiàn)重試風(fēng)暴時(shí),可以遠(yuǎn)程下發(fā)指令關(guān)閉系統(tǒng)的重試功能。在一些大規(guī)模的促銷活動(dòng)之前,我們也可以提前預(yù)估峰值 QPS,決定是否要提前關(guān)閉重試。

增加內(nèi)部系統(tǒng)承載能力,是指容量規(guī)劃和擴(kuò)容。容量規(guī)劃通常依賴于壓測(cè)的指標(biāo)情況,根據(jù)系統(tǒng)壓力的上限,來合理評(píng)估和圈定服務(wù)器、數(shù)據(jù)庫、緩存、消息中間件等各種資源的需求上限,并提前預(yù)備好資源配額。

擴(kuò)容一般包括按計(jì)劃內(nèi)擴(kuò)容和緊急擴(kuò)容。日常工作中會(huì)我們可以巡檢系統(tǒng)的流量、數(shù)據(jù)量和容量,當(dāng)發(fā)現(xiàn)當(dāng)前系統(tǒng)承載能力已不能滿足或即將不能滿足容量需求時(shí),需要執(zhí)行擴(kuò)容。緊急擴(kuò)容通常發(fā)生在過載時(shí),這類擴(kuò)容要求迅速、無差錯(cuò),這對(duì)系統(tǒng)的彈性伸縮能力要求很高。關(guān)于彈性伸縮,后面會(huì)單獨(dú)說明。

1.9.輪值

Oncall 輪值是面向人員的可靠性措施,利用“人為治理“的思路,為“技術(shù)治理”提供有益的補(bǔ)充。Oncall 對(duì)在線服務(wù)尤其是互聯(lián)網(wǎng)業(yè)務(wù)來說,是必不可少的一個(gè)環(huán)節(jié)。

1.9.1.有效的 Oncall

按照 Oncall 輪值的規(guī)模和模式,通常可以劃分為兩種情況:

專業(yè)運(yùn)維團(tuán)隊(duì):在一個(gè)小規(guī)模的 IT 企業(yè)及業(yè)務(wù)部門中,通常會(huì)設(shè)置專業(yè)的運(yùn)維團(tuán)隊(duì),該團(tuán)隊(duì)對(duì)所有系統(tǒng)的運(yùn)行時(shí)狀態(tài)進(jìn)行 7*24 小時(shí)無間斷監(jiān)控和巡檢,發(fā)出預(yù)警、處理和總結(jié)故障。這種方式的好處是各司其職,業(yè)務(wù)團(tuán)隊(duì)并不需要對(duì)運(yùn)維部分負(fù)責(zé),運(yùn)維團(tuán)隊(duì)也不需要關(guān)心業(yè)務(wù)和開發(fā)。

DevOps 文化:隨著企業(yè)規(guī)模的擴(kuò)大及各種技術(shù)棧成熟度的提升,很多企業(yè)不再為各業(yè)務(wù)線設(shè)立獨(dú)立的運(yùn)維團(tuán)隊(duì),而是奉行 DevOps 文化。簡單理解就是研發(fā)和運(yùn)維的界限開始變得模糊,大部分情況都是,研發(fā)團(tuán)隊(duì)同時(shí)也需要充當(dāng)運(yùn)維的角色。

不管采用哪種方式,都必須秉承幾個(gè)基本的 Oncall 原則:

有合理的 Oncall 責(zé)任人排班。一般來說,每個(gè)人輪值一周的粒度比較恰當(dāng),既不會(huì)太疲憊,又不至于人員頻繁交接帶來額外成本。

對(duì)于 Oncall 責(zé)任人來說,應(yīng)該在輪值周期內(nèi)減免其他工作事項(xiàng)。比如對(duì)研發(fā)人員來說,Oncall 的一周內(nèi)不應(yīng)該再安排研發(fā)任務(wù),這樣有利于提升 Oncall 的專注度;

人員需要有備份。建議每個(gè) Oncall 責(zé)任人的背后都應(yīng)該至少有一個(gè) Backup;

建立良好的 Oncall 規(guī)范,保證 Oncall 有章可依;

以下是一個(gè)實(shí)際的 Oncall 值日規(guī)范,供各位讀者參考:

1. 值班目標(biāo)? 通過告警推送(電話、IM、短信、郵件)、系統(tǒng)巡檢(監(jiān)控、日志等)等方式,及時(shí)發(fā)現(xiàn)系統(tǒng)異常并處理;? 接收并處理內(nèi)部人員或外部用戶報(bào)告的線上問題;2. 系統(tǒng)巡檢2.1 巡檢方式系統(tǒng)監(jiān)控:按照值班報(bào)告,對(duì)后端的系統(tǒng)進(jìn)行監(jiān)控巡檢,并留意告警監(jiān)控詳見:XXX 系統(tǒng)日志:在必要情況下,需要登錄服務(wù)器,觀察系統(tǒng)日志,重點(diǎn)查看異常日志(Exception,Error)服務(wù)器詳見:XXX 2.2問題處理發(fā)現(xiàn)問題,或執(zhí)行線上操作,需要及時(shí)周知項(xiàng)目組!!禁止私自做線上操作!!當(dāng)出現(xiàn)以下指標(biāo)異常時(shí):? 系統(tǒng)QPS過高或過低,超過警戒線? 系統(tǒng)響應(yīng)時(shí)間過高或過低,超過警戒線? 系統(tǒng)錯(cuò)誤率升高,超過警戒線;導(dǎo)致異常的可能原因有:? 基礎(chǔ)設(shè)施:如服務(wù)器、系統(tǒng)、網(wǎng)絡(luò)、接入層、存儲(chǔ)、消息中間件等故障;? 外部服務(wù):如推薦服務(wù)、廣告服務(wù)、直播服務(wù)等對(duì)外依賴的服務(wù)故障;? 系統(tǒng)缺陷:系統(tǒng)BUG導(dǎo)致的故障,如功能問題、性能問題;需要采取的措施:? 保留證據(jù),如監(jiān)控截圖,日志保存,現(xiàn)場信息Dump等;? 對(duì)于緊急情況(如影響線上業(yè)務(wù)),必要情況可執(zhí)行重啟操作;? 對(duì)于非緊急情況,可嘗試定位問題并hotfix處理;? 對(duì)于無法處理的問題,需要第一時(shí)間聯(lián)系owner;

復(fù)制

1.9.2.Oncall 記錄與故障總結(jié)

Oncall 值日生必然會(huì)發(fā)現(xiàn)、處理線上故障,這就意味著必須記錄和總結(jié)故障。故障報(bào)告應(yīng)該有固定的格式規(guī)范,便于復(fù)盤總結(jié)。以下是一個(gè)參考 Google SRE 規(guī)范而制定的故障報(bào)告模板和部分樣例:

1.故障總體描述1.1 故障摘要//簡單描繪故障基本情況2020-07-29日,由于代碼誤操作,將一條測(cè)試廣告引入到線上Feed流中; 1.2 開始時(shí)間//故障開始時(shí)間,精確到分2020-07-29 16:20 1.3 結(jié)束時(shí)間//故障結(jié)束時(shí)間,精確到分2020-07-30 08:12 1.4 影響時(shí)間//故障持續(xù)的時(shí)間,精確到分17h52min 1.5 影響范圍//故障的業(yè)務(wù)影響,如影響多少用戶,影響多少數(shù)據(jù),影響XX用戶體驗(yàn),影響XX效果日期 展現(xiàn)pv 展現(xiàn)uv 計(jì)費(fèi)點(diǎn)擊(已去重)2020-07-29 96598 20059 16462020-07-30 21741 7511 325累計(jì)影響點(diǎn)擊1971人次 1.6 觸發(fā)條件//能復(fù)現(xiàn)故障的步驟1.Feed流內(nèi)容自動(dòng)播放超過X秒,出現(xiàn)“這是一條測(cè)試廣告”的內(nèi)容廣告;2.Feed流點(diǎn)擊內(nèi)容進(jìn)入播放頁面,播放超過X秒,出現(xiàn)“這是一條測(cè)試廣告”的內(nèi)容廣告;3.點(diǎn)擊該內(nèi)容廣告,導(dǎo)流到一個(gè)無效的Web頁面; 1.7 根本原因//故障的根本原因,一般有:基礎(chǔ)設(shè)施、外部服務(wù)、系統(tǒng)缺陷、流程規(guī)范等由于測(cè)試缺乏數(shù)據(jù),開發(fā)為配合廣告QA測(cè)試,在代碼中寫死Mock數(shù)據(jù),上線時(shí)忘記刪掉; 1.8 修復(fù)措施//故障的解決方案描述去掉Mock數(shù)據(jù),上線修復(fù); 1.9 發(fā)現(xiàn)途徑//故障的發(fā)現(xiàn)方式,一般有:業(yè)務(wù)報(bào)障、報(bào)警、主動(dòng)巡檢等業(yè)務(wù)報(bào)障 2.經(jīng)驗(yàn)總結(jié)2.1 好的方面//本次故障處理中,做的好的經(jīng)驗(yàn)總結(jié)定位到問題后,響應(yīng)及時(shí),修復(fù)上線速度較快; 2.2 壞的方面//本次故障處理中,做的不好的經(jīng)驗(yàn)教訓(xùn)1.問題發(fā)現(xiàn)不夠及時(shí),等待業(yè)務(wù)報(bào)障才開始處理;2.業(yè)務(wù)類數(shù)據(jù)無法觸發(fā)告警,自動(dòng)化用例尚未覆蓋該場景;3.處理問題時(shí),出現(xiàn)一次誤判(時(shí)間線里有說明);4.開發(fā)代碼自查,以及Peer Code Review不夠充分;5.線上回測(cè)不夠充分; 2.3 僥幸的方面//本次故障處理中,僥幸的方面使得損失沒有擴(kuò)大 3.未來改進(jìn)措施//針對(duì)本次故障需要改進(jìn)的措施,包括不限于:架構(gòu)升級(jí)優(yōu)化、系統(tǒng)查漏補(bǔ)缺、加強(qiáng)流程規(guī)范、升級(jí)監(jiān)控告警等1.減少不必要的硬編碼來Mock數(shù)據(jù),改為利用Mock配置后臺(tái),更安全高效;;2.Mock配置后臺(tái)目前在Feed服務(wù)中已具備,Q3會(huì)推廣到其他10來個(gè)系統(tǒng)中,達(dá)到80%以上覆蓋率;3.自動(dòng)化用例增加廣告字段檢測(cè)能力,提前發(fā)現(xiàn)問題,預(yù)計(jì)本周五前完成 ;4.應(yīng)給予研發(fā)更多的Code Review時(shí)間Buffer,在開發(fā)環(huán)節(jié)發(fā)現(xiàn)更多問題;5.QA應(yīng)充分回測(cè),多做冒煙測(cè)試,后端QA也建議增加前端驗(yàn)證環(huán)節(jié),更全面發(fā)現(xiàn)問題;6.對(duì)代碼Mock,需要增加“//TODO:上線前刪除以下mock代碼”,然后可以通過自動(dòng)化工具檢查,有這種注釋的代碼不應(yīng)該通過Code Review; 4.時(shí)間線//故障處理流水線,時(shí)間精確到分。如:2020-07-22 10:30 系統(tǒng)告警,值班人員開始查看監(jiān)控2020-07-29 16:20 開發(fā)A上線需求 (Merge Request地址)該Merge Request中攜帶一條硬編碼的Mock數(shù)據(jù),問題開始發(fā)生;2020-07-29 23:07 業(yè)務(wù)反饋Feed流自動(dòng)播放及對(duì)應(yīng)的播放頁面,出現(xiàn)“這是一條測(cè)試廣告”內(nèi)容廣告;2020-07-29 23:29 業(yè)務(wù)將該問題通知到開發(fā)和測(cè)試團(tuán)隊(duì);2020-07-29 23:34 值日生B判斷該問題為內(nèi)容廣告業(yè)務(wù)方向,由于需求在評(píng)審時(shí)邏輯是:廣告由播放后臺(tái)加載,認(rèn)為該邏輯可能是播放后臺(tái)的問題,等待QA報(bào)障(此處存在誤判);2020-07-30 06:40 值日生B進(jìn)一步思考,認(rèn)為可能存在后端因素,查了之前的需求,發(fā)現(xiàn)實(shí)現(xiàn)過程中邏輯有變動(dòng)。斷定是后端上線引起。2020-07-30 07:00 值日生B抓包分析,發(fā)現(xiàn)后端下發(fā)恒定的廣告Mock字段,開始查閱29號(hào)上線的Merge Request,發(fā)現(xiàn)問題代碼;2020-07-30 07:32 值日生B呼叫開發(fā)A,簡單溝通原因及修復(fù)措施,開發(fā)A在路上不能快速上線;2020-07-30 07:43值日生B呼叫開發(fā)C,快速溝通問題及修復(fù)措施,開發(fā)C開始修復(fù)上線;2020-07-30 07:51開發(fā)C開始發(fā)布對(duì)Hotfix進(jìn)行灰度發(fā)布;2020-07-30 08:12 上線完畢,出現(xiàn)部分容器資源不足無法更新,和基礎(chǔ)架構(gòu)同事溝通緊急摘除,系統(tǒng)全部更新完畢;2020-07-30 08:30 經(jīng)過半小時(shí)到一小時(shí)的線上檢查,確定問題得以修復(fù);

復(fù)制

1.10.變更管理

不知道讀者有沒有留意到一個(gè)現(xiàn)象,工作日經(jīng)常會(huì)遇到各種系統(tǒng)不穩(wěn)定:網(wǎng)絡(luò)抖動(dòng)、第三方服務(wù)耗時(shí)突增、服務(wù)器負(fù)載突然上升又快速回落,等等。而同樣的現(xiàn)象在節(jié)假日尤其是較長的法定節(jié)假日反而不容易出現(xiàn)。

經(jīng)驗(yàn)表明,90%以上的線上故障基本都是由變更引起的,因此,勢(shì)必要高度重視變更帶來的影響。變更不僅僅意味著代碼的改動(dòng)和發(fā)布,也包括容易被忽視的配置變更和數(shù)據(jù)變更。本章節(jié)來討論下這三種變更的管理。

1.10.1.代碼變更

發(fā)布無小事。代碼變更是最常見、最頻繁的變化方式,代碼變更應(yīng)該遵循以下原則:

1.必須要有完備的編碼規(guī)范來指導(dǎo)日常開發(fā)。包括命名、常量、格式、異常、日志、監(jiān)控,等等。另外還需要有代碼格式化和代碼檢查插件,自動(dòng)對(duì)代碼進(jìn)行格式化和規(guī)格檢查,未通過檢查的代碼應(yīng)該不允許提交到遠(yuǎn)程倉庫,也不允許發(fā)布。

2.必須要有嚴(yán)格的 Code Review 規(guī)范。可以采用生成 Merge Request 來貫穿于開發(fā)、自測(cè)、QA 測(cè)試、預(yù)發(fā)布和正式發(fā)布環(huán)節(jié)。Code Review 應(yīng)該采用技術(shù)手段來強(qiáng)制執(zhí)行,沒有 Merge Request 的代碼變更不應(yīng)該通過測(cè)試,更不應(yīng)該被線上發(fā)布平臺(tái)接受。

3.必須要有自動(dòng)化代碼分析。包括白盒分析(如 SonarQube)和黑盒自動(dòng)化用例執(zhí)行。當(dāng)這些代碼變更的掃描結(jié)果不符合預(yù)期時(shí),代碼不允許合并到主干,也不允許發(fā)布。

4.必須要有上線管理工具,對(duì)代碼變更上線進(jìn)行審批和流程跟蹤,便于將來追溯。

5.必須要采用漸進(jìn)式方式來發(fā)布代碼變更。如常見的預(yù)上線(Staging)發(fā)布、金絲雀(Canary)發(fā)布、藍(lán)綠發(fā)布等,可以執(zhí)行一部分灰度流量先上線并觀測(cè)指標(biāo)變化(包括技術(shù)指標(biāo)和業(yè)務(wù)指標(biāo)),當(dāng)指標(biāo)符合預(yù)期時(shí),可以考慮發(fā)布剩下的流量。需要注意,全量發(fā)布也應(yīng)該漸進(jìn)式、滾動(dòng)式進(jìn)行,因?yàn)榧词构δ苷9ぷ?#xff0c;也可能會(huì)在發(fā)布過程中出現(xiàn)性能和可靠性異常。

6.必須要有回滾預(yù)案。需要注意的是,回滾盡可能不要重新拉取主干或上一個(gè)標(biāo)簽的代碼并重新打包,一方面會(huì)影響回滾速度,另一方面可能發(fā)布異常是基礎(chǔ)代碼或打包過程出現(xiàn)問題導(dǎo)致,即使是上一個(gè)版本重新多次打包也可能無濟(jì)于事,這種情況現(xiàn)實(shí)環(huán)境中是出現(xiàn)過的。因此,應(yīng)該有一種基于版本鏡像的回滾機(jī)制,即拉取任意版本的包鏡像,直接快速部署,達(dá)到本地快速回滾的目的。

1.10.2.配置變更

配置變更一般指配置文件、各種配置后臺(tái)、管理后臺(tái)中技術(shù)參數(shù)的配置變更。這些變更幾乎不被人重視,但往往是導(dǎo)致系統(tǒng)故障的罪魁禍?zhǔn)住?/p>

筆者的觀點(diǎn)是,任何技術(shù)參數(shù)的變更,必須要有 Peer Review 機(jī)制,即使這些后臺(tái)沒有類似 GitHub 的原生 Pull Request 機(jī)制,也需要第三方研發(fā)人員了解該變更,評(píng)估改動(dòng)風(fēng)險(xiǎn)并執(zhí)行發(fā)布。

1.10.3.數(shù)據(jù)變更

研發(fā)人員不到萬不得已的情況,不要輕易到存儲(chǔ)系統(tǒng)中修改數(shù)據(jù)。如果確實(shí)由于 BUG 導(dǎo)致臟數(shù)據(jù),需要批量變更數(shù)據(jù),應(yīng)該采用腳本(SQL 或編程實(shí)現(xiàn))來控制變更的安全性,并且需要第三方研發(fā)人員執(zhí)行 Peer Review。在數(shù)據(jù)變更的過程中,需要實(shí)時(shí)監(jiān)控?cái)?shù)據(jù)的變化,發(fā)現(xiàn)異常需要立即撤銷變更操作。

總結(jié)

以上是生活随笔為你收集整理的微服务架构-系统可靠性保障的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。