微服务架构-系统可靠性保障
1.可靠性
可靠性(Reliability)是指微服務系統在面對異常情況時,如關鍵組件損壞、流量或數據量異常、延遲波動、級聯故障傳導、分布式集群雪崩、系統過載等等,能夠持續保持穩定運行或快速恢復的能力。
當我們在說可靠性時,我們到底在談什么?是指高可用架構設計?系統容忍宕機的時間?彈性能力、自愈能力?還是指故障的轉移和恢復時間?
本文試圖從以下幾個方面來說明一個高可用架構所需的必備因素:概念與度量、故障體系、單點治理、超時、重試、限流、降級、熔斷、Oncall 輪值與變更管理。
相信在這些方法論和實戰經驗相結合、多管齊下的協助下,能最大限度改善和保障系統的可靠性,讓微服務系統可以固若金湯,具備較強的韌性。
1.1.概念與度量
首先需要說明的是,我們在談及可靠性時,往往會把以下幾個相關的概念弄混淆:可靠性、可用性、彈性、持久性、冗余性。這些似乎都是和系統穩定性有關的近義詞,但實際上是存在區別的。
1. 可靠性(Reliability)。可靠性是指系統能夠正常工作和穩定運行的時間,這里的穩定性代表功能性操作正確無誤,且性能表現符合預期。
2. 可用性(Availability)。可用性是指系統可觸達的時間,一般是指服務或數據能夠連續提供給用戶的時間,或可用時間的占比。
3. 彈性(Resiliency)。彈性本質上是指一種修復能力,代表系統在組件失敗或遇到災難后的恢復能力。彈性能力一般由系統故障修復時間來衡量。
4. 持久性(Durability)。持久性是指數據能否具備持久化、穩定存儲的能力,不會隨著時間變動而輕易流失。和服務不同,持久性更側重于數據層面的穩定性。
5. 冗余性(Redundancy)。冗余性是指系統是否存在多個副本,互為備份,也稱為系統的冗余度。冗余度越高,系統的災備能力就越強。
舉個綜合的例子來說明,假設有一個視頻網站,對用戶提供 7*24 小時視頻展示和播放服務。該視頻網站具備以下特征:
- 該網站每年頂多宕機 5 分鐘;
- 經常會出現頁面加載不完整,比如會出現 CSS 無法加載而導致的頁面參差不齊;
- 視頻偶爾會出現播放到一半的時候,出現長時間卡頓;
- 該網站在請求延遲升高的時候,能在 1 分鐘內迅速恢復;
- 該網站的數據做了完整的冷備,備份介質采用磁帶和光盤,且異地保存。任何時候都可以快速恢復數據;
- 網站采用了異地多活的物理架構部署,服務器和中間件采用 N+3 的 Buffer 來設計;
不難看出,該視頻網站具備很高的可用性,因為宕機時間足夠短,用戶幾乎在任何時候都可以訪問。但是可靠性比較糟糕,因為頁面經常無法正常加載,視頻播放體驗也不盡如人意。網站的彈性恢復能力很強,不到 1 分鐘就能從故障中恢復。另外,網站具備很優秀的數據持久化能力,由于備份和恢復的存在,數據幾乎不用擔心丟失。網站的冗余度能達到 N+3,意味著系統架構具備較高的災備程度。
以上這些概念,通常來說在不同的上下文中具備不同的釋義。除非特別說明,默認情況下本文不會有意區分這些名詞術語,而是統一采用廣義的可靠性概念來表達系統穩定性語義。
可靠性的常見度量指標,是基于系統可用時間計算出來的比例,即 R(%) =? (uptime/uptime + downtime) ?* 100%,常見的 SLA 指標會借助多少個 9 來表示,如圖 1?1 所示。
圖 1?1 常見 SLA 指標
還有一種可靠性度量指標是利用 MTTR、MTTF 和 MTBR 來表示,如圖 1?2 所示。
- MTTR ( Mean Time To Repair),平均故障修復時間。指系統從發生故障到故障修復的時間間隔之平均值;
- MTTF ( Mean Time To Failure),平均無故障時間。指系統從正常運行到故障發生的時間間隔之平均值;
- MTBF ( Mean Time Between Failure),平均故障間隔時間。指系統在兩次故障發生之間的時間間隔之平均值;
圖 1?2 MTTR、MTTF 和 MTBR 的關系
這種度量指標下,可靠性通常用 R(%)? = (MTTF/MTBR)? * 100%? =? (MTTF/MTTR + MTTF) * 100%來表示。
SLA 指標每提升一個 9,背后就需要付出較大的努力和人力、資源消耗。一般來說,大部分互聯網企業的關鍵業務可以達到 4 個 9,部分金融級別的業務系統或公有云會承諾 5 個 9。對大部分企業來說,需要根據自身的實力和業務需要,合理評估 SLA 需求,不要一味的去追求極高的 SLA,其投資回報比(ROI)可能并不高。
1.2.故障體系
故障體系是一套科學的方法論,用于指導和管理日常的系統故障。根據互聯網企業的實踐經驗總結,再結合 Google SRE 標準,我們試著給出一個標準的、完整的故障管理體系,包括:故障畫像、故障預案、故障演練、故障轉移、故障恢復。
1.2.1.故障畫像
故障畫像是故障體系和故障處理流程的源頭及理論依據,所有線上問題的發生、發現和處理幾乎都是率屬于故障畫像所窮舉的各種范疇。
故障畫像本質上來說就是通過分析大量的故障案例,進行充分總結和高度抽象得出的故障根因(Root Cause)。常見的故障畫像大概分為以下幾類:
1. 基礎設施
常見的基礎設施故障包括以下組成部分:
機房設施故障:如電力系統故障、空調系統故障等一系列 IDC 機房底層相關的環境因素。
服務器故障:常見的有物理機、虛擬機、容器的系統宕機和指標異常。宕機包括計劃內和計劃外,服務器指標異常包括 CPU 使用率異常,內存使用率過高,SWAP 過于頻繁、網絡、磁盤等設備 I/O 讀寫異常,中斷及上下文切換頻次過高等等。對于虛擬機、容器來說,還會存在資源超賣導致的流量高峰期系統平均負載頻繁抖動。
網絡故障:網絡問題是影響面最大的故障因素,往往會導致 P0 級別的生產事故。常見的有網絡中斷、丟包、重復、延遲、交換機路由器等設備故障、網絡專線故障等等。
接入層故障:常見的問題有 DNS 解析失敗、負載均衡 SLB 故障、VIP 轉移故障、Nginx 請求轉發異常(如路徑解析錯誤、健康檢查機制失敗)等。
2. 中間件故障
常見的中間件故障包括以下組成部分:
存儲系統故障:一般指數據庫(MySQL、MongoDB、HBase、Cassandra 等 SQL 或 NoSQL 數據庫)、緩存、分布式存儲系統、分布式對象系統(OSS)等廣義上的存儲系統存在的故障點,如:系統單點,存儲系統只部署了單實例或單機房。這這種情況下,如果發生單實例宕機或單機房故障,或單實例讀寫流量過高、數據量較大導致的慢查詢、Load 升高等負載問題,由于沒有更多的冗余,使得系統無法進行故障轉移。
消息中間件故障:作為削峰填谷和解耦的利器,消息中間件被大量使用在異步化場景中。但消息中間件并不能保證長久穩定運行。如:數據量過大導致磁盤被填滿,從而使得集群不可用;讀寫壓力過大導致 MQ 集群出現 GC 頻繁、節點脫離集群等故障,如 ActiveMQ 的 Network Broker 模式,很容易在大流量的讀寫壓力下導致 Broker 斷開連接,影響到總體可用性。
3. 外部服務
一般是指第三方服務(如 REST API/RPC/消息等)的故障,如服務超時、HTTP 響應狀態碼異常、服務過載、返回報文異常等。這類故障是出現頻次最高的,需要有重點預案、演練和監控。
4. 系統缺陷
一般是指我們服務自身的功能、性能或穩定性問題,如:JVM 內存溢出、頻繁 GC 停頓、代碼死循環、CPU/內存/磁盤使用率異常、系統過載、響應時間過高、功能性 BUG 等。
5. 流程問題
流程問題一般是人為誤操作或流程不夠標準造成的故障,如代碼缺少 Code Review、缺乏漸進式灰度發布機制、缺乏充分的功能或性能測試、缺乏監控告警等。這類問題應該盡量避免。
1.2.2.故障預案
凡事預則立,不預則廢。針對上一節描述的基礎設施、中間件、外部服務、系統缺陷和流程問題等故障畫像,我們需要擬定一套成熟的故障應對預案。目標是在故障突發時,能夠使故障處理流程做到有章可依、有條不紊、敏捷高效。
以下是筆者結合自身的實際經驗總結,整理出的一個故障預案模板,供參考:
1 基礎設施故障1.1 服務器故障【問題】宿主機(物理機)故障導致的一個或多個虛擬機實例宕機,或虛擬機發生計劃外(不明原因)的重啟;【預案】一個虛擬機實例宕機一般影響較小,確定負載均衡的自動健康檢查已將流量轉走,待虛擬機恢復后重新部署應用。注:正在調研服務器重啟時自動觸發Jenkins部署以減少人工運維;【預案】多個虛擬機實例宕機需評估影響范圍,極端情況可能會造成流量擊垮其他服務器,緊急情況需啟用備用虛擬機。確定負載均衡的自動健康檢查已將流量轉走; 【問題】服務器(包括物理機、虛擬機和容器)一項或多項指標異常,如平均負載升高、內存空間不足、磁盤空間不足、CPU消耗過高、I/O消耗過高、文件句柄泄露等,導致程序無法正常運行;【預案】在基礎監控系統中查看服務器指標變化情況;【預案】根據指標變化找到原因,解決問題。如程序中資源釋放、JVM調優、清磁盤機制優化等; 1.2 網絡故障【問題】機房網絡誤操作(網絡割接/板卡升級替換/打補丁/設備升級/配置優化/擴容/虛擬網絡組件升級等),或部分網絡設備故障,造成一臺或多臺服務器級別網絡問題(內網不通、丟包、延遲等);【預案】將問題反饋到網絡組;【預案】一臺服務器網絡問題一般影響較小,確定負載均衡的自動健康檢查已將流量轉走,并關注網絡恢復情況;【預案】多臺服務器網絡問題需評估影響范圍,必要情況需要切流量。確定負載均衡的自動健康檢查已將流量轉走; 【問題】機房核心交換機等大型故障,造成子網級別網絡問題,或機房級別網絡問題;【預案】將問題反饋到網絡組;【預案】若網絡故障影響到負載均衡SLB,則通過控制臺修改DNS配置,將流量導向其他正常SLB,并等待DNS緩存更新;【預案】若影響到轉發前置機Nginx,通過SLB配置后臺,將流量導向其他正常Nginx;【預案】若影響到服務器,通過Nginx配置將流量導向其他正常的服務器; 【問題】運營商問題或網絡流量過大,造成專線問題,或專線帶寬打滿;【預案】將問題反饋到網絡組;【預案】參考上面預案; 1.3 電力故障【問題】機房例行檢修(倒閘檢修/柴油發電帶載等)導致故障,或意外停電故障,造成機房無法正常運行;【預案】若影響到負載均衡SLB,則通過控制臺修改DNS配置,將流量導向其他正常SLB,并等待DNS緩存更新;【預案】若影響到Nginx,通過SLB配置將流量導向其他正常Nginx; 1.4 接入層故障【問題】DNS故障,無法解析【預案】公司層面報障,切換客戶端DNS高可用配置,開啟備用DNS域名; 【問題】SLB故障,如VIP無法訪問,或丟包;【預案】通知SLB運維人員;【預案】SLB部署需要做到:1)外網:同一個運營商出口會配置2個不同機房SLB,2)內網:同一個內網域名會配置多個不同機房SLB用于冷備;【預案】通過控制臺修改DNS將流量導向其他正常SLB,并等待DNS緩存更新 ; 【問題】Nginx故障;【預案】Nginx前置機部署時需要跨機房;【預案】通過SLB配置將流量導向其他正常Nginx; 2 中間件故障2.1 存儲故障【問題】MySQL故障,無法訪問或訪問超時;【預案】要求部署時必須是Master-Slave架構且跨機房;【預案】遇到單實例故障或機房故障時,會自動進行Failover且切換主從,業務方會經歷一段有損服務后自行恢復; 【問題】MongoDB故障,無法訪問或訪問超時;【預案】要求部署時必須是跨機房;【預案】遇到單實例故障時,會自動進行Failover且重新選舉Primary,業務方會經歷一段有損服務后自行恢復; 【問題】HBase故障,無法訪問或訪問超時;需要封裝客戶端代理SDK(內置配置中心開關),底層做雙向數據復制;遇到集群故障時,通過配置中心切換到另一個集群; 【問題】Couchbase故障,無法訪問或訪問超時;需要封裝客戶端代理SDK(內置配置中心開關),底層做XDCR數據復制;遇到集群故障時,通過配置中心切換到另一個集群; 【問題】Redis故障,無法訪問或訪問超時;【預案】要求部署必須是Master-Slave架構且跨機房;【預案】遇到到單實例故障時,會自動進行Failover且切換主從,業務方會經歷一段有損服務后自行恢復; 2.2 搜索系統故障【問題】Elasticsearch故障,無法訪問或訪問超時【預案】通過客戶端代理組件,將讀寫流量切換到備用Elasticsearch集群; 2.3 消息中間件故障【問題】ActiveMQ故障,無法訪問或訪問超時【預案】通過客戶端代理組件,將讀寫流量切換到備用ActiveMQ集群; 【問題】Kafka故障,無法訪問或訪問超時【預案】通過客戶端代理組件,將讀寫流量切換到備用Kafka集群; 2.4 分布式系統故障【問題】Zookeeper故障,無法訪問或訪問超時;【預案】等待Zookeeper完成奔潰恢復和重新選舉,密切觀察監控指標變化; 3.外部服務故障【問題】外部服務出現調用超時或異常返回;【預案】在編碼時務必處理好第三方調用的超時、重試、降級與熔斷機制,做好監控告警與日志埋點,并對異常情況做好測試;【預案】遇到故障時,啟動手動或自動降級熔斷,使得調用快速失敗和快速返回兜底數據,避免調用鏈雪崩;復制
1.2.3.故障演練與混沌工程
光說不練假把式。故障演練是整個故障管理體系中最重要的一環。缺乏真實演練尤其是生產環境的真實故障演練,故障預案則一文不值。線上環境的故障演練能真實反映系統的潛在故障點,驗證監控、告警及日志系統的及時性和有效性,也能高效驗證故障預案和處理流程的實戰效果。
企業、部門乃至業務團隊應該成立故障演練小組,制定完備的演練規劃、方案和執行計劃,定期或不定期進行生產環境的演練,并生成故障演練報告和跟蹤項,做到及時發現和解決各種故障隱患。
隨著 Netflix 的 Chaos Engineering 思想和部分頭部互聯網公司的實踐(如阿里的 Chaos Blade),混沌工程開始進入了國內眾多工程師的視野,風靡大江南北,且有愈演愈烈的趨勢。混沌工程的基本原則主要有:
- 建立穩定狀態的假設;
- 多樣化現實世界事件;
- 在生產環境運行實驗;
- 持續自動化運行實驗;
- 最小化“爆炸半徑”;
我們可以根據混沌工程的方法論和工具包,探索和開發自動化混沌測試方案,支持基礎設施、中間件、服務的自動故障注入和測試。通過在生產環境設置定時器,可以支持預先編排好的混沌測試用例自動化執行,可以盡早發現系統的可靠性隱患。以上操作可以在混沌測試平臺上進行開發、配置、部署、自動化運行和監控。
以下是根據一個實際生
產環境故障注入案例,經過整理得到的混沌測試用例:
1.模擬虛擬機VM CPU滿載時間:2021-08-20 00:00~00:30執行:8核CPU使用率均達到100%期望:基礎監控可觀察到CPU使用率上升,系統告警。應用監控顯示該節點工作不正常并及時告警。負載均衡自動摘除不健康節點。 2.模擬虛擬機VM 內存完全占用時間:2021-08-20 00:30~01:00執行:32GB RAM使用率達到100%期望:基礎監控可觀察到MEM使用率上升,系統告警。應用監控顯示該節點工作不正常并及時告警。負載均衡自動摘除不健康節點。 3.模擬虛擬機VM 磁盤I/O完全占用時間:2021-08-20 01:00~01:30執行:磁盤I/O使用率達到100%期望:基礎監控可觀察到磁盤I/O使用率上升,系統告警。應用監控顯示該節點工作不正常并及時告警。負載均衡自動摘除不健康節點。 4.模擬虛擬機VM 磁盤完全填充時間:2021-08-20 01:30~02:00執行:300GB磁盤使用率達到100%期望:基礎監控可觀察到磁盤使用率上升,系統告警,無法寫入。應用監控顯示該節點工作不正常并及時告警。負載均衡自動摘除不健康節點。 5.模擬虛擬機VM 宕機時間:2021-08-20 02:00~02:30執行:將該虛擬機實例關閉期望:基礎監控可觀察到虛機關閉,系統告警。應用監控顯示該節點工作不正常并及時告警。負載均衡自動摘除不健康節點。 6.模擬Kubernetes Pod宕機時間:2021-08-20 02:30~03:00執行:將某Workload下的Pod關閉期望:基礎監控可觀察到虛機關閉,系統告警。應用監控顯示該節點工作不正常并及時告警。負載均衡自動摘除不健康節點。Kubernetes自動啟動新的Pod。 7.模擬不同物理機的虛擬機、Pod宕機時間:2021-08-20 03:00~03:30執行:將隸屬于不同物理機的虛擬機和Pod關閉期望:基礎監控可觀察到虛機關閉,系統告警。應用監控顯示該節點工作不正常并及時告警。負載均衡自動摘除不健康節點。Kubernetes自動啟動新的Pod。 8.模擬單機房網絡故障時間:2021-08-20 03:30~04:00執行:通過模擬網絡延遲、丟包、專線斷開等方式,實現單一機房網絡通訊故障期望:基礎監控可觀察到虛機關閉,系統告警。應用監控顯示該節點工作不正常并及時告警。 9.模擬MySQL故障時間:2021-08-20 04:00~04:30執行:將MySQL Master節點和Slave節點分別關閉期望:基礎監控可觀察到虛機關閉,系統告警。應用監控顯示該節點工作不正常并及時告警。MySQL主從集群自動提升Slave為主節點,并自動修改域名綁定。應用層面感知不明顯。 10.模擬推薦服務故障時間:2021-08-20 04:30~05:00執行:通過制造網絡延遲及丟包,模擬推薦服務故障期望:應用監控顯示該節點工作不正常并及時告警。推薦服務(強依賴服務)被自動降級到緩存數據,推薦效果出現折損。 11.模擬用戶服務故障時間:2021-08-20 05:00~05:30執行:通過制造網絡延遲及丟包,模擬用戶服務故障期望:應用監控顯示該節點工作不正常并及時告警。用戶服務被自動熔斷,業面上大部分用戶的關鍵信息(如頭像、昵稱)出現丟失,主體服務不受影響。復制
以上給出了一些基本的混沌測試注入案例,覆蓋了基礎設施(服務器、網絡)、中間件(存儲系統)和外部服務(強依賴服務、弱依賴服務)等。實際執行混沌測試時,可參考這些案例,并靈活變動。
1.2.4.故障轉移
根據墨菲定律,該發生的故障終究會發生。盡管我們做了大量的故障預案和演練,但只要系統存在薄弱環節(幾乎 100%無法避免),則遲早會被攻破,問題也會爆發。
在故障發生時,故障轉移(Failover)手段就顯得尤為重要,好的轉移技術手段能有效縮短平均故障修復時間 MTTR,減少系統、數據、資金、公司信譽損失,也能將用戶體驗影響降到最低。
故障轉移基本原理是利用 HA 監控組件,實時追蹤和發現系統的故障點,并自動執行故障點轉移,將服務流量和數據遷移到冗余的組件上。
需要說明的是,這里的組件是一個廣義的概念,可以是一個物理機、虛擬機、容器,也可以是一個集群或集群節點,再大一點可以是 IDC 機房、AZ 可用區或地理位置 Region。
故障轉移主要有兩種模式:主動-主動模式和主動-被動模式。
主動-主動模式(Active-Active):主動-主動模式是指組件之間相互熱備,且正常承擔讀寫流量。在故障發生時,HA 監控組件檢測到不健康組件后,對其進行摘除或屏蔽,避免流量訪問。
舉例來說明,常見的主動-主動模式有無狀態的服務器集群,或去中心化的存儲集群。
如 REST API 服務集群,多節點提供服務,由接入層提供負載均衡、鑒權及流量路由。這種情況可以視為一種無狀態的主動-主動模式。當單一節點或多個節點發生故障(宕機、服務器 CPU/MEM/DISK/NETWORK 指標異常等)時,由接入層的健康檢查組件自動檢測出不健康狀態的節點,并將這些節點從集群臨時剔除。
另一種情況是無中心的存儲集群,如 Couchbase。當某一節點宕機后,集群會將該節點屏蔽,將讀寫流量轉移到其他節點。
主動-被動模式(Active-Passive):主動-被動模式是指備用組件平時不會提供服務,僅充當冷備的角色。當故障發生時,由 HA 監控組件將不健康組件進行摘除處理,同時將流量導入備用節點。
這種情況需要格外小心,很多時候備用節點往往只是在冷備和待命,在關鍵時刻可能會“掉鏈子”,不能正常工作。在故障切換時,有時候會發生流量打到備用設備后,備用組件再次出現問題,故障影響面反而被再次放大。
1.2.5.故障恢復
故障恢復是故障處理的收尾動作,當故障轉移完畢,就應該對故障組件進行及時修復,這可能是一個手動或自動的處理過程。
故障組件恢復后,通常會面臨兩個選擇:將流量再次轉移回已恢復的組件,恢復到故障前的拓撲結構;另一種方案就是將恢復的組件加入到總體架構,充當備用角色。
故障恢復的時間應該盡可能短,并且可控。因為故障轉以后,系統總體可能會處于“單點”的狀態,如果故障組件不能很快恢復并再次加入系統,則又會增加長時間單點的風險。如果此時剩下的組件再次發生故障,系統就會出現無組件可轉移的問題。
舉一個實際生產環境發生的例子來說明。某 Feed 服務集群,物理架構上采用 2 個機房來部署節點,假設為 IDC1 和 IDC2。在某個晚高峰,IDC1 出現核心交換機網絡故障,所有服務器實例無法建立網絡連接,機房總體不可用,運維人員緊急將 IDC1 從負載均衡設備上進行摘除。
IDC1 在接下來的 2 天都沒有完全恢復,不幸的事情發生了,IDC2 在另一個晚高峰也出現了網絡故障,這個系統徹底癱瘓了。
這里先不討論基礎架構的薄弱及運維能力的欠缺,單從故障恢復的層面來看,我們應當遵循“盡早恢復”的原則,將故障組件盡可能快速、高效的恢復和重新加入系統。
1.3.單點治理
從這一節開始,我們來逐步介紹提升微服務系統可靠性的手段。
分布式系統存在單點故障(Single?Point?of?Failure,SPOF),是故障頻發且無法收斂的一個重要原因。故障本身是不可避免的,但是當問題發生時,如果系統單點導致無法進行及時的 Failover,則系統可靠性就會大打折扣。因此,系統的單點治理迫在眉睫,故障的單點治理水平也是衡量一個系統可靠性的重要指標。
單點治理的核心思想是提升冗余度,不管是無狀態的服務,還是有狀態的存儲、中間件,都可以通過冗余部署的方式,形成同構、同質的集群化架構,從而達到壓力分攤、互相備份與切換的效果。
1.3.1.組件類型與粒度
在梳理系統單點時,必須要弄清楚系統組件的類型和粒度,這些內容通常也代表了故障發生的顆粒度。常見的粒度有:
服務器:服務器是系統賴以生存的基本運行時環境,通常包括物理機、虛擬機和容器。服務器的粒度可以簡單按物理機、機架、機柜、機房、地域來劃分。具體可歸納總結為:
- 單臺物理機、單一虛擬機或容器實例;
- 來自同一機架或機柜的多臺物理機,來自同一物理機的多個虛擬機、容器實例;
- 來自不同機架或機柜的多臺物理機,來自不同物理機的多個虛擬機、容器實例;
- 來自同一機房的多個物理機、虛擬機和容器;
- 來自不同機房的多個物理機、虛擬機和容器;
- 來自同一地域的多個物理機、虛擬機和容器;
- 來自不同地域的多個物理機、虛擬機和容器;
中間件:中間件通常包括存儲(數據庫、緩存等)、消息中間件、搜索中間件、微服務組件等各類除服務器之外的基礎設施。中間件以單實例和集群化的部署架構最為常見,集群化往往使用場景更普遍,很多中間件提供了原生的集群解決方案,如 Redis Cluster、Kafka、MongoDB、HBase、Elasticsearch 等;
中間件的實例本身也是由服務器構成,這里不再重復贅述服務器的單點情況,而是直接列舉中間件的拓撲單點:
- 中間件只有單實例;
- 中間件為集群架構,包含多實例,分布在同機房;
- 中間件為集群架構,包含多實例,分布在同地域的不同機房;
- 中間件為集群架構,包含多實例,分布在不同地域的不同機房;
現代的企業級、分布式物理架構基本都是多機房、多可用區和多地理位置部署,本文觀點是,如果不特別指出,默認的單點粒度至少是機房級別,即系統至少應該跨機房部署,以及具備跨機房容災能力。
從以上列舉的服務器和中間件組件的粒度可以看出,有很多種粒度類型其實是存在單點風險的,亟待治理。
如何進行單點治理,提升系統冗余度、彈性和可用性?通常見仁見智,各企業、機構、各架構師的解決方案通常會不一樣,并沒有標準答案。本文試圖給出一種經過實踐的冗余高可用方案,如圖 1?3 所示。
圖 1?3 一種跨地理位置的多數據中心物理架構
這是一種在實際生產環境中驗證過的多數據中心物理架構。物理層面,由華北 Region 和華南 Region 組成,每個 Region 又由 3 個物理 IDC 機房組成。邏輯層面,包括接入層、服務層和中間件組件。下面
來分析每一層的潛在單點故障風險,以及對應的冗余方案和故障轉移措施。
1.3.2.接入層高可用
接入層包括 DNS 域名智能解析、SLB 負載均衡以及 Nginx 反向代理。
DNS 域名解析:DNS 域名智能解析,根據用戶的地理位置和運營商進行智能解析,將請求流量引流到離用戶最近的 SLB 負載均衡 VIP 上。
通常會針對每一組 VIP,設置多個 SLB 負載均衡互相熱備,流量可以打到任意一個 SLB 上,這種方案既可以起到負載均衡、分攤壓力的作用,還可以達到冗余、故障轉移的目的。
這樣做的好處可以使得用戶就近接入,避免跨地理位置處理請求事務,造成不必要的延遲。比如北京移動用戶,就會優先訪問部署在北京移動機房的 SLB 負載均衡。
DNS 智能解析故障包括兩方面:
1. 局部解析失效,或無法解析到正確的 VIP 上,如圖 1?3 中 1 所示。在實際環境中,偶爾會發生,特別容易發生在解析策略比較細的情況下。比如,北京聯通的用戶,可能會被解析位于河北機房的 VIP 上。還有一種情況是局部解析策略失效,如北京電信的用戶無法解析。
由于配置了多種解析策略以及多組 VIP(每組又包含了 N 個 SLB 組件),因此,當故障發生時,完全可以通過調整 DNS 解析策略,將故障域的用戶請求解析到正常的 VIP 上。
2. DNS 域名解析完全失效,如圖 1?3 中 2 所示。這是一種極其嚴重、災難性的單點故障,也是很容易被忽略的一種場景,會導致客戶端訪問完全無計可施,所有網站和 APP 頁面均無法加載。
一種常見的解決方案是采用多 DNS 域名機制。客戶端預先對服務端提供的 DNS 做冗余,埋點備用 DNS 域名,最好采用 2 個以上的備用域名。
當故障發生時,通過遠程配置中心下發切換指令,進行域名切換。或者客戶端會植入負載均衡和健康檢查算法,當探測到當前 DNS 域名不可訪問時,可自動切換到備用域名上,這種能力通常會被封裝成組件或 SDK,供客戶端透明的使用。
SLB 負載均衡:SLB 負載均衡主要是提供一個高可用的集群,對外通過 VIP 暴露訪問端點。通常采用硬件設備,或 LVS、HAProxy 之類的軟件實現。SLB 的重點是高可用的 VIP 機制,以及負載均衡、健康檢查、SSL 卸載機制,通常只做流量轉發。
SLB 的故障通常有兩種:
1. 單 SLB 故障,如圖 1?3 中 3 所示。通常是 VIP 漂移失敗導致。解決方案也很簡單,直接在 DSN 解析層面,將該 SLB 的 VIP 摘除即可。業務層面需要接受短暫的 DNS 緩存帶來的請求失敗問題。
2.多 SLB 故障,如圖 1?3 中 4 所示。這種情況不常見,通常是多個 SLB 部署在一個物理相關的設備下導致,如共享一個機架機柜、共享一個機房或網絡設備。在故障預案層面,需要將多 SLB 進行合理的分散部署,至少需要跨 2 個機房。
當問題發生時,由于我們有多組 SLB,可以修改 DNS 解析策略,將故障組進行隔離,流量導入其他組 SLB 即可。
Nginx 反向代理:Nginx 反向代理的作用主要是提供限流、黑白名單、鑒權、流量轉發、監控、日志等功能,也是眾多 API 網關得以實現的基礎組件(如 OpenResty、 Kong)。
Nginx 的物理部署架構和 SLB 完全不同,一般是按業務機房進行部署的,作為業務系統在當前機房的前置機。這樣做的好處是,一旦發生機房級別故障,直接摘除 Nginx 集群即可快速對流量進行阻斷和隔離。
Nginx 反向代理的單點故障通常有兩種:
1. Nginx 單機故障,如圖 1?3 中 5 所示。這種情況很常見,因為 Nginx 本身也是借助服務器建立的服務,服務器的各種問題當然也會導致 Nginx 故障。解決方案也很簡單,由上層的 SLB 通過健康檢查,自動摘除即可。
2.一組 Nginx 故障,如圖 1?3 中 6 所示。通常由軟件 BUG 或機房級別故障導致,這種問題發生比例不高,但確實會存在。解決方案是由 SLB 自動摘除該組 Nginx,流量自動被旁路到其他機房。
1.3.3.服務層高可用
這里的服務層一般指無狀態業務集群,即任何一個服務實例均不存儲數據,除了一些可隨時失效(Invalidate)或剔除(Evict)的本地緩存,以及寫入本地磁盤的日志日志。業務集群無狀態的好處是顯而易見的,可以有效的提升系統靈活性、伸縮性和故障轉移速度。
服務層的單點問題有兩種:
1. 單一服務器實例故障,如圖 1?3 中 9 所示。一般是由服務器自身的故障點導致,這種問題的發生概率非常高,當集群規模達到 1000 以上的實例時,幾乎每天都會隨機出現 1~5 個實例故障。
當單一實例故障時,通常不需要采取任何手動措施,而是由上層的 Nginx 代理通過健康檢查來自動摘除不健康實例。
2. 多服務器實例故障,如圖 1?3 中 10 所示。一般是虛擬機、容器對應的宿主機故障導致,當然也可能會由程序 BUG 觸發或性能問題導致,如不合理的超時、重試設置導致的服務雪崩,流量突增導致的服務過載等,往往會將該服務集群直接壓垮。
當多實例故障發生時,故障面相對較大,可能在借助 Nginx 自動健康檢查摘除的同時,需要人工介入。
值得注意的是,Nginx 的健康檢查機制和 Proxy 重試一般是基于 Upstream 的延遲和 HTTP 狀態碼進行判斷的。當 Upstream 節點宕機或進程退出時,Nginx 是很容易檢測并將其剔除。然后,現實情況并不總是這樣,之前的故障演練里也提到過,服務器節點可能會發生 CPU、存儲、磁盤、網絡的負載指標不正常,對外的表現通常是耗時時高時低,很不穩定,這種情況 Nginx 不一定能檢測和判斷準確,往往會導致不能及時摘除,或者相反,導致誤判。
因此,一個高效、精準的健康檢查機制至關重要,有條件的讀者可以嘗試自行研發一些組件,通過讀取監控數據來智能分析故障點,并預測問題發生的時間和部位,實現自動 Failover。
1.3.4.中間件高可用
很多中間件都提供了原生的集群部署能力,如互聯網業務系統常見的面向 OLTP 的存儲系統:MySQL、Redis、MongoDB、HBase、Couchbase、Cassandra、Elasticsearch 等;消息中間件如 RocketMQ、Kafka 等;分布式協調服務如 Chubby、Zookeeper 等。
這里討論的也是這種集群化架構的冗余能力,如果讀者的生產系統中間件尚未具備多實例的集群部署,建議盡快對架構進行升級換代。
集群化的中間件天然消除了單實例問題,但這樣就能萬無一失、永保平安了么?顯然不是,我們來分析下常見的中間件故障點以及應對措施。
以常見的存儲系統為例,通常有主從式(Master-Slave)和去中心化兩種拓撲架構模式。如 MySQL(主從式)、Redis(3.0 版本以下或主從式)、MongoDB(復制集)、Zookeeper 就是采用經典的主從式架構,而 Couchbase、Cassandra 這類 NoSQL 存儲則是采用無中心的架構。
主從式架構:主從式集群通常以讀寫分離的方式為客戶端提供服務,即所有應用節點寫入 Master 節點,多個 Slave 組合并采用負載均衡(服務端代理或 DNS 域名)的方式分攤讀請求。
當主從式集群的 Master 實例發生故障時(如圖 1?3 中 11 所示),通常會由健康檢查組件自動檢測,執行重新選舉,將集群的 Slave 節點提升為 Master。整個過程對客戶端透明,切換時間視具體數據量和網絡狀況而變化,當數據量很小時,客戶端幾乎無感知。
當 Slave 實例發生故障時(如圖 1?3 中 12 所示),處理流程相對簡單,只需要將故障節點從負載均衡摘除即可。
無中心架構:去中心話的架構簡單高效,以 Cassandra 為例,任何節點均可支持讀寫以及請求轉發,數據通過一致性哈希的方式進行分片,并且在其他節點上保存副本,客戶端可隨意調整一致性級別(Consistency Level)來在讀寫性能、強弱一致性語義之間達到平衡。
當節點發生故障時(如圖 3?3 中 13 所示),集群會自動識別到故障節點,并進行摘除。數據會發生 Rehash,而客戶端也會執行 Failover 操作,挑選其他健康的協調節點,重新建立連接。
1.3.5.同城多中心
前面的章節重點介紹了實例級別、分組級別和集群級別的故障點以及冗余、故障轉移方法,并沒有提及機房級別故障。然而,機房級別故障確實是頻繁發生的問題,需要引起重視。
在實際生產環境中,尤其是需要保持 7*24 小時高可用的互聯網業務,不可能只部署一個機房,而是采用“同城多中心”的方式,來消除機房級別的單點故障,如圖 3?3 所示,通過負載均衡和前置機轉發,實現了南北流量及東西流量在多機房的調度和轉移。
一般來說,企業會在分布在各地理位置的數據中心建立多機房,如在華北數據中心建立 3 個 IDC,依次編號為 HB-IDC-01、HB-IDC-02 和 HB-IDC-03。
還有一種數據中心的建設方式也比較常見,即遵循 Region-AZ-IDC 的設計模式,其中 Region 就是地理位置,如華北、華南。AZ(Available Zone)指可用區,表示應用的最小部署單元,通常由多個 IDC 組成。
除非特別指定,本文通篇默認會遵循“地理位置-數據中心-機房”的設計模式。
如圖 1?3 中 7 標注所示,當 HB-IDC-03 出現故障時,整個機房將不可用。這種情況時有發生,不可避免。原因也很復雜,可能是機房基礎設施故障(如電力系統問題、溫度、濕度失調),也可能是網絡故障(如核心交換機出錯、網絡割接誤操作等)導致。
常見的故障轉移方式在故障預案中有提及過。接入層面,通過調整各級組件(DNS、SLB、Nginx 等),實現下一級接入層安全轉移;服務層面,通過調整接入層,對流量進行重新調度,將故障機房的服務進行隔離;中間件層面,通過集群的健康檢查機制,調整集群拓撲和讀寫方式。
1.3.6.兩地三中心
前面提到了機房級別的故障,實際中還會存在地域級別的故障,一般由自然災害(暴雨、洪澇災害、地震等)或骨干網中斷(如光纖被挖斷)導致。因此,對于規模較大、可靠性要求較高(尤其是金融級別)的業務系統,靠一個地理位置數據中心來支撐流量顯然是不夠的。因此,很多公司從容災的角度考慮,建立了“兩地三中心”機制。
所謂兩地三中心,是指在兩地建立三個數據中心,兩地之間通常需要保持 1000 公里以上的距離,避免距離太近導致兩地一起失效,反而起不到災備效果。
以華北兩個數據中心,華南一個災備中心來舉例說明。業務系統在華北兩個個數據中心正常提供服務,而華南數據中心一般不提供服務,偶爾也會提供少部分讀服務。生產環境產生的數據,會異步復制到華南災備中心。
當華北的兩個數據中心出現重大故障時,可以將用戶流量切換到華南災備中心,由該數據中心接管線上業務請求。
正如故障轉移章節提到的,兩地三中心有一個很大的弊端,在于災備中心通常是冷備角色,平時不會頻繁的進行切換演練,或者幾乎就不會考慮演練。關鍵時刻可能就會由于各部件失效、或過載,導致沒法承接流量。另外一個問題就在于,冷備中心一般需要和兩個主數據中心的容量一致,但又不會提供活躍的服務,這會導致嚴重的資源浪費。
鑒于此,我們需要考慮異地多活的部署架構,下一章節會重點說明。?
1.3.7.異地多活
異地多活架構可以說是高可用物理架構中的終極形態。
大型的跨國公司(如 Google、Amazon、Microsoft)業務系統繁多且復雜度高,服務的用戶也會遍布全球,因此往往會在全球主要戰略位置建立多個數據中心。
圖 1?4 全球數據中心分布樣例
如圖 1?4 所示,是一個大規模的公有云服務(如 Amazon AWS,Microsoft Azure 等)在全球的數據中心分布:北美、南美、歐洲、亞太、澳洲、非洲等。
國內的很多互聯網業務(如電商、社交、視頻、廣告、出行、本地服務等)也爭先恐后在全國各地建立了多個數據中心,常見的有:華北、華東、華南、華中等。
如此規模的異地多活物理架構部署,挑戰性是毋庸置疑的。主要來自兩個方面:
1. 數據的復制延遲。跨地域的網絡情況不容樂觀,很容易發生延遲升高、丟包率升高。而數據在各個數據中心的復制也會隨之受到影響,數據不能高效及時的復制到目標數據中心,就會導致用戶訪問的數據出現延遲和不一致,有時候用戶體驗是不可接受的。
2. 一致性要求與寫沖突。某些業務要求的一致性較高,甚至是強一致,在跨地域復制的情況下幾乎是不可能實現的。另外,有些存儲系統如果設計成多點寫入的話,則會出現寫入沖突,如何解決沖突也是一個比較棘手的問題。
如圖 1?3 所示,通過 DNS 智能解析,將不同地理位置的用戶就近接入當地數據中心。在數據中心內部,服務集群一定是本地部署的,而中間件集群則會根據不同的中間件特點而獨立設計:
- 一種設計模式,是單一中間件集群橫跨各數據中心,通常是類似于 MySQL 的 Master-Slave 架構。寫入操作回流到 Master 節點所在數據中心執行單點寫入,再讀取本地 Slave 節點以提升性能。這種方式比較常見,因為操作簡便,缺點是寫入性能差,當數據中心之間網絡發生分區后,寫入只得被迫中斷。另外會帶來數據復制延遲問題。
- 另一種設計模式,也是單一中間件集群橫跨各數據中心,通常是類似于 Cassandra 的去中心化結構。可以支持多點寫入,這樣讀、寫操作就可以在本地數據中心完成。性能表現較好,但會帶來數據復制延遲和沖突修復的問題。
- 還有一種設計模式,是在每個數據中心部署獨立的集群,本地直接執行讀、寫操作,中間件集群之間跨地域復制數據。性能也比較好,但同樣會帶來數據復制延遲和沖突修復的問題。
不難看出,無狀態的服務在異地多活架構中可以做到游刃有余,只需要調度流量即可。但數據層面卻成了阻礙多活架構的核心焦點。為了解決以上問題,很多公司嘗試了 Sharding 化部署的思想,比如阿里的單元化架構設計。
Sharding 化部署的核心思路,在于將用戶流量集中在一個數據中心完成,完成交易的封閉處理,即同一個事務請求處理以及對應的數據,不應該跨數據中心。
常見的設計方案就是選擇 Sharding Key(比如用戶 ID),在接入層將請求會話路由和粘滯到對應的機房單元。數據層面也是根據該 Sharding Key 進行路由讀寫。路由算法是穩定的,因此無論該用戶發起多少次請求,處理流程和對應數據都一定會進入對應的部署單元處理,不會出現由于跨單元而出現數據不一致的問題。
仔細思考一下,這種 Sharding 化部署真的無懈可擊嗎?不一定!最常見的問題就是維度的變化使得讀寫必須要橫跨數據中心。以電商業務為例來說明,假設存在買家、賣家和商品維度,當前選取的 Sharding Key 為買家 ID,也就是說同一買家的任意請求都會落到同一數據中心來處理,包括產生的數據也會落到該中心的存儲系統中。
如果買家下單后,同時要求減少商品庫存,如果庫存不足還要對該商品進行下架。另外,還需要給買家增加信譽度積分。如果以上這些操作要求是強一致的,即下單后需要馬上看到庫存變化和賣家積分變化在頁面上同步顯示,這種場景通過 Sharding 化的多活架構就沒法實現。當然,如果可以接受最終一致,則可以通過消息中間件,將數據變化同步到其他的數據中心,頁面經過一段延遲后即可顯示變化。
顯然,異地多活是沒有銀彈的,很難做到高性能、強一致性和高可用性都能同時得到滿足,這和 CAP 的原理也很相似。?
1.3.8.容易忽視的 Worker 高可用
Worker 類組件是微服務架構中不可或缺的一部分,但其高可用卻最容易被忽視,因為這一類組件往往默默無聞在背后工作,卻又擔任著重要的角色,一旦失效,可能報表就無法生成,數據預處理就會失敗,緩存預加載的數據就會丟失。
Worker 類的高可用關鍵在于“監視”和冗余部署,當有合適的 HA 監視組件發現 Worker 不工作或狀態不健康,并能及時執行 Failover,則問題就可以迎刃而解。
有一類 Worker 通常是消息中間件的消費者(Consumer),由于消息中間件天然具備消息投遞的負載均衡和節點發現能力,所以這類 Worker 應用也就很容易具備高可用特性。當出現消費節點宕機或消費緩慢問題,消息中間件會自動停止消息投遞。
而大部分自研的 Worker 類應用,由于不存在 HA 監控,再加上系統往往以單實例的方式部署,因此不具備任何高可用。我們可以設計一套分布式的架構,提升系統可用性,如圖 1?5 所示。
圖 1?5 一種高可用的分布式 Worker 設計
以 Zookeeper 為協調中心,設置 Leader 和多個 Follower 節點。其中,Leader 節點接受來自控制平面(Control Plane)的任務分配和一系列控制指令,而 Follower 節點則會執行 Leader 分配的任務。Follower 可以設計成 Active-Active 模式或 Active-Passive 模式。
當 Leader 或 Follower 節點宕機時,會觸發 Zookeeper 的 ephemeral znode 感知到事件并通知所有節點,從而觸發一次新的選舉或任務 Rebalance,這些操作可以利用一些 high-level 的組件如 curator 來輔助實現,無需從底層開發。
1.4.超時
無數慘痛的生產環境事故和經驗教訓表明,不正確的超時設置是造成微服務級聯故障和雪崩的頭號殺手。遺憾的是,大量的工程師完全沒有意識到這一點,每年都有大量的線上服務在超時方面反復栽跟頭。
本章節就來聊一聊超時的問題、預防措施和經驗總結。
1.4.1.超時與雪崩
微服務的分布式特性,使得服務之間的調用和互操作極其頻繁,隨著業務的拓展,服務間調用管用關系也會變得錯綜復雜,如圖 1?6 所示。
圖 1?6 微服務間調用關系
如果服務間調用未設置超時,或超時設置不合理,則會帶來級聯故障風險。當某一系統發生故障時,服務不可用,上游就會出現調用延遲升高。如果沒有合理的超時參數控制,則故障就會順著調用鏈級聯傳播,最終導致關鍵路徑甚至所有服務不可用,如圖 1?7 所示。
圖 1?7 由微服務 G 故障導致的大部分服務不可用
這種級聯故障現象也稱為“雪崩”,雪崩帶來的影響不僅僅是響應慢,更嚴重的是會耗盡系統資源,使得整個系統完全癱瘓。
以基于 Spring Boot 開發的微服務為例,默認的 Tomcat 連接池大小為 200,也就是說默認單實例只允許同時存在 200 個并發請求。這在平時是毫無壓力的,但雪崩發生時,所有的請求就會一直在等待,連接池迅速就被占滿,從而導致其他請求無法進入,系統直接癱瘓。
要想解決雪崩問題,就必須設置合理的超時參數。以 Java 應用來說,常見的超時設置主要有 HttpClient 和各類中間件系統,尤其是數據庫、緩存。一般來說,服務間調用超時和數據庫訪問,建議設置超時時間不超過 500ms,緩存類超時時間不超過 200ms。
1.4.2.警惕不合理的連接池超時設置
有一類超時問題比較隱蔽而且風險很高,缺乏經驗的工程師很難發現。以 HttpClient 連接池來說,通常大部分人都正確設置了創建連接超時(ConnectTimeout)和讀取超時(SocketTimeout),但卻忽略了連接池獲取連接超時(ConnectionRequestTimeout)的設置。
當目標服務超時發生,有時候會發現盡管設置了讀取超時,系統還是會出現雪崩。原因就是連接池獲取連接默認是無限等待,這就導致了當前請求被掛起,直到系統資源被耗盡。這里給出一種實際生產環境使用的配置。
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(500).setSocketTimeout(500).setConnectTimeout(500).build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();cm.setMaxTotal(maxTotal);// 整個連接池最大連接數cm.setDefaultMaxPerRoute(maxPerRoute);// 每路由最大連接數,默認值是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();復制
當發生讀取超時的時候,當前路由的并發連接數迅速被占滿,無連接可用。新的業務請求在等待 500ms 后就會退出請求,從而有效保護了服務不被堆積的請求壓垮。
1.4.3.動態超時與自適應超時
實際場景中,如果對所有的服務調用超時都搞“一刀切”,比如都設置為 500ms,則會過于死板,缺乏靈活性。比如有些服務調用量并不高,但是延遲偏高,而有些服務性能高,TP99 可能才不到 100ms,服務提供方也能承諾服務的性能可以長期得到保證。
這種情況就可以考慮動態超時和自適應超時方案。
所謂動態超時,是指可以通過控制后臺,人為在運行時干預超時參數。還是以 HttpClient 為例說明,可以通過配置中心,針對某些 API URL 動態調整參數,代碼樣例如下:
// 配置中心控制接口超時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);}復制
所謂自適應超時,本質上是一種自動化的動態超時。可以在服務調用方實時監控目標服務的調用 QPS、耗時和錯誤率,當檢測到耗時較低,則可以預測后續的耗時情況并調整參數配置。如果出現大量的超時,自適應控制也可以將超時閾值進一步調低,避免調用鏈路上耗時升高帶來不必要的損失。
1.4.4.超時的套娃原則
理想情況下,超時的參數配置應該是遵循“套娃原則”,即沿著調用鏈,超時的閾值設定應該是逐級減小的。
如果超時是逐級增大的,則會出現:在上游已超時返回的情況下,下游還在繼續處理,造成不必要的資源浪費。如果反過來,上游還在等待,下游可能已超時并進行再次重試,這樣當前請求的成功率就會得到提升。
1.5.重試
重試是一把雙刃劍,既是提升服務間調用成功率、容錯的一種重要手段,也是造成流量放大、服務過載的原因之一。
1.5.1.為什么要重試
當微服務系統功能無法正常工作,或遠程調用失敗時,往往需要重試機制,在有限的時間段內來提升調用成功率。
服務調用的重試與否,需要看場景,如果對業務處理的成功率要求很高且目標服務可以承諾冪等性,可以增加重試。重試必須具備上限,不可以執行無限制的、反復的嘗試。
重試的位置無處不在,既可以是來自客戶端的用戶手動重試,也可以是服務端各組件之間的自動重試。
當客戶端出現全部或局部頁面加載失敗時,可以通過友好的文字、圖片等方式來引導用戶手動重試加載,如提示語“網絡似乎開了點小差,請再次重試”。
在服務端,接入層也可以增加重試能力,常見的就是 Nginx 的代理重試。如以下配置:
#重試設置proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_504 | off; //出現哪些情況,會請求其他后端服務器重試,off則不重試;proxy_next_upstream_timeout 10s; //即proxy_next_upstream_timeout時間內允許嘗試proxy_next_upstream_tries次;proxy_next_upstream_tries 2; //復制
而應用層重試一般指 HTTP API 調用或 RPC 服務調用的重試設置,也包括各種中間件 SDK 自帶的原生重試能力。
1.5.2.重試風暴
毋容置疑,重試會放大請求量。重試觸發的條件一般是目標服務或中間件系統出現了不健康狀態或不可用,在這種情況下,無論是來自客戶端的用戶重試或來自服務的組件間的重試,都會引起“讀放大”效應。這會給原本就處于故障狀態的組件雪上加霜,極端情況下會導致系統直接奔潰。
我們把這種由于大量重試導致的瞬間流量放大造成的類似 DDoS 攻擊效應,稱為“重試風暴”。重試風暴是造成系統過載和奔潰的重要原因,需要努力避免。
1.5.3.退避原則
為了減少重試風暴帶來的危害,一種行之有效的方法是增加重試的時間間隔,通過退避(back-off)的方法來逐步增加等待時間。最常見的做法是指數退避(exponential back-off)原則。
舉個例子,設置初始重試等待時間為 10ms,重試上限為 5 次。當目標系統出現故障時,調用方等待 10ms 后發起重試,如果請求依舊失敗,則客戶端等待 20ms 后再次發起重試。如果再次請求失敗,則等待 40ms 后再次重試,以此類推,直到返回正確的結果或達到重試上限。
1.5.4.指數退避的風險
指數退避的特性會使得重試間隔時間按指數級別遞增,在極端情況下,會導致單次請求的耗時被嚴重放大,從而導致系統資源被耗盡,進一步拖垮系統。需要引起格外注意。
建議減少初始等待時間,并且嚴格限制重試次數上限,比如只重試一次。
1.5.5.動態重試
為了兼顧重試帶來成功率提升的收益,以及減少重試風暴帶來的流量放大和耗時提升。我們可以考慮采用動態重試方案來進一步提升系統的靈活性。
通過在服務調用方預先植入動態開關邏輯,可以在運行時動態調整重試參數。包括:
- 開啟和停止重試功能;
- 調整重試次數上限;
- 調整重試模式,是普通的重試操作,還是指數退避重試;
- 如果是指數退避,可以調整初始重試間隔時間;
以上操作既可以是全局操作,也可以按系統、或目標服務的顆粒度進行操作。
1.6.限流
限流是保護業務系統的必不可少的環節。當流量突增時,一個擁有良好限流設計的系統能夠抗住流量,快速丟棄多余的請求,讓內部的微服務系統不受影響。
限流是一種有損的可靠性方案,限流生效時,有部分用戶是無法正常加載頁面的。同一用戶也可能會出現正常訪問和被限流交替發生。盡管如此,限流仍是抵御突發流量的不二法門,有損的服務一定勝過服務被全量壓垮。
1.6.1.限流的位置與粒度
和超時、重試一樣,限流的位置也是遍布到微服務的各組件,甚至是客戶端應用。通常離用戶越近的位置,限流效果越明顯。
常見的限流位置有客戶端限流、接入層限流和服務層限流。客戶端可以對單一用戶的操進行限流,避免用戶反復重試,比如可以在用戶下單后,將按鈕置灰,防止用戶多次重試。接入層限流是服務端最有效的位置,可以通過令牌桶或漏桶算法,對遠程 IP 進行限流,或對下游服務進行限流。應用層限流一般為單機限流,具體限流閾值通常以單機壓測的結果為基準進行估算。
限流的粒度可以是全局限流,也可以是服務粒度,或者是 API 根目錄,甚至可以設置為特定的 API URL。這些粒度應該可以支持在控制后臺動態配置。
1.6.2.主動限流與被動限流
所謂主動限流,是指服務的提供方主動評估服務的容量和峰值 QPS,提前配置限流閾值并說明限流后的服務表現。服務的使用方無需關心這些服務的性能和可靠性,只需要按照限流的標準進行容錯處理即可。這種方式是一種比較友好的合作模式。
被動限流則恰恰相反,服務的提供方無法了解和評估自身的服務狀態,上游流量突增后也不具備技術手段來應對。這種情況可以考慮服務調用方實施被動限流,即對服務的使用方、各種存儲、中間件等資源增加限流約束機制,理想情況應該可以支持控制后臺隨時調整。
1.6.3.警惕泄洪流量
有一種情況很容易被忽略,當一組消費者(Consumer)同時處理來自消息中間件的消息時,往往由于某些內部組件的延遲(如寫入存儲緩慢、第三方服務延遲升高等)或上游消息量突增導致消息積壓,一般會修復慢的組件或增加更多的消費者來解決這些問題。當這些瓶頸解除后,消費者的處理速度會大幅提升,瞬間積壓的消息會被大量處理,從而導致下游系統出現過載現象,或出現主從數據同步出現大量的滯后(Lag)。我們姑且稱這種流量為“泄洪流量”。
泄洪流量在真實場景中經常會發生,而且會帶來嚴重的影響,因為很多系統的設計(如 CQRS 架構風格)出于資源限制、或架構的簡潔性考慮,往往會讓這些消費者和線上服務共享存儲資源(尤其是寫庫)或調用公共服務。當泄洪流量發生時,這些存儲資源可能就會出現負載極速上升、主從數據同步 Lag 被拉大,公共服務甚至可能會被立刻打垮。
解決方案其實很簡單,消費者的應用集群也應該和在線服務一樣,設置限流機制。
1.7.降級熔斷
降級、熔斷是另外一種保護手段,這是一種“棄卒保車”的制勝策略。當局部系統或組件不可靠時,通過對該故障域進行降級、熔斷處理,并展示有損的降級數據,從而達到快速隔離故障的目的,且用戶體驗犧牲不明顯。降級熔斷的關鍵在于識別問題和降級策略。
1.7.1.降級的位置與粒度
和限流很相似,降級的位置也是越多越好,降級層次越多,系統就越靈活可控。通常可降級的位置有客戶端、接入層和應用層。
客戶端降級可以有效抵御大量的無效請求入侵服務端系統。當客戶端識別到后端服務工作在不健康狀態時,可以執行本地降級,屏蔽一些操作(如評論加載),并且將預先埋入的提示語展示給用戶,如“評論似乎開了一點小差,請稍后再試”。
當接入層檢測到 Upstream 層服務有故障時,如延遲升高、響應狀態碼不符合預期等,可以對該服務請求執行“快速失敗”處理,向請求方輸出錯誤提示,或輸出預先緩存的退化數據。
應用層的降級相對更靈活,可以設置很多降級策略,如基于請求 QPS、請求的長尾延遲、超時率或錯誤率等,并且可以提前根據不同策略處理好降級數據。
降級的粒度可以是全局限流,也可以是服務粒度,或者是 API 根目錄,甚至可以設置為特定的 API URL。這些粒度應該可以支持在控制后臺動態配置。
1.7.2.主動降級與被動降級
主動降級是指直接將對外提供的服務(如 RESTful API)降級掉,輸出降級錯誤提示,或一組緩存的業務數據,這些數據通常不是那么及時,甚至是“臟”數據。主動降級是一種粗粒度的降級。
被動降級是指將不健康的第三方服務或組件降級,這通常是一種細粒度的降級策略。降級的結果就是當前調用無法返回數據,或者返回緩存的舊數據,基于這些降級數據,服務端再處理本次請求事務。
1.7.3.強弱依賴
微服務架構的依賴非常多,比如服務間調用(HTTP/RPC)、數據庫讀取、緩存訪問、消息中間件訂閱與消費等等,這些依賴項構成了微服務系統的拓撲結構。
根據業務的不同,有些依賴是必不可少的,當出現故障時,整個大系統就面臨著不可用的風險,我們把這種依賴稱為“強依賴”。比如 Feed 業務中的推薦服務,就是一種典型的強依賴,當推薦服務不可用,整個 Feed 流就面臨著無數據可用的困境。
有些依賴項在出現故障時,可以丟棄,業務上不會產生明顯的影響,我們稱之為“弱依賴”。比如在 Feed 業務中的用戶服務和緩存,當出現問題時,完全可以拋棄,對用戶的影響就是每條 Feed 的作者頭像和昵稱丟失,業務層面一般可以接受。
微服務架構設計的一個重要準則就是一切盡可能弱依賴,解除強依賴。這意味著在代碼開發階段,需要面向失敗設計,做好依賴項失敗的降級處理。
1.7.4.降級數據
降級就意味著丟棄弱依賴、解除強依賴,意味著需要輸出退化的降級數據給調用方,降級數據的準備是有技巧的。我們來分析下常見降級數據和請求的關系:
- 降級數據和用戶無相關,如商品的基本信息,并不會隨著用戶的不同而發生變化;
- 降級數據和用戶強相關,如訂單列表、購物車等,不同用戶的數據完全不一樣;
- 降級數據和用戶弱相關,如視頻播放,視頻的基本播放屬性不隨用戶變化,但鑒權部分會隨著免費、付費用戶的不同而存在區別;
好的,有了這三種降級數據類型,我們就可以有針對的去準備數據。
一種建議的方案就是在正常讀取依賴數據后,異步寫入降級存儲系統,這個存儲一般由大存儲量的 NoSQL 數據庫來承擔即可,可以有效提升降級數據的寫入和讀取效率。對于用戶無相關的數據,可以設置維度 Key,如 fallback_product_<pid>標識了某商品的 Key,并將數據以 Value 的形式寫入存儲;對于用戶強相關和弱相關的數據,Key 需要增加用戶維度,如 fallback_order_<orderid>_uid_<uid>表示某用戶的訂單數據。
1.7.5.熔斷
從某種意義上來說,超時和限流可以認為是一種低級形態的降級策略,而熔斷則是一種高級形態的降級。
熔斷器設計模式是一種很經典的彈性容錯算法,如圖 1?8 所示。當檢測到系統指標出現異常并且達到一定的閾值后,熔斷器就會自動打開,從而切斷對依賴性的調用,然后可以根據策略選擇一份降級數據。當等待時間超過預設的門檻值后,熔斷器會嘗試半關閉狀態,部分請求開始調用真實的依賴項,當結果符合成功率標準時,熔斷器會關閉,反之則熔斷器再次打開,依次類推。
熔斷器的好處是顯而易見的,使用熔斷器可以在問題累計到一定的程度后,直接斷開依賴、快速失敗,從而有效保護系統本身和依賴方,避免全量系統發生雪崩。
圖 1?8 微服務熔斷器設計模式
常見的開源熔斷器實現有 Hystrix 及其后繼者 Resillence4j、Sentinel 等。感興趣的讀者可以自行閱讀和調研官方文檔,并評估是否可以應用到自身微服務項目中。
使用熔斷器需要注意幾個問題:
- 有些熔斷器組件是代碼高侵入的,但粒度細、可控性強,實際使用時需要在靈活性和代碼可維護性方面仔細權衡利弊;
- 使用熔斷器是有額外性能開銷(Overhead)的,比如 Hystrix 的線程池隔離模式,會按需創建一個或多個線程池,這些線程會占用更多的 CPU 和內存。有條件的讀者完全可以自行設計輕量級的熔斷器;
- 一定要根據實際情況尤其是壓測指標,設置好門檻值(Threshold),避免狀態發生誤判,造成不必要的線上故障;
1.8.過載
流量的過載是影響系統可靠性、導致服務不可用的的一個重要因素。筆者曾經經歷過由于代碼缺陷導致的流量被放大到 9 倍,服務器和存儲系統的資源(CPU、內存、網絡帶寬、磁盤 I/O)在不到 5 分鐘的時間內就迅速消耗殆盡,系統無法正常提供對外服務,幾乎所有業務系統都未能幸免,其結果是災難性的。
本章節來分析下過載的原因以及解決方案。
1.8.1.過載的原因
過載的根本原因是流量發生突增,但系統資源承載能力不足。這里的資源包括但不限于:CPU 計算能力、內存大小、外存(磁盤、SSD 等)容量、設備 I/O 速度、網絡帶寬、實例個數、中間件處理能力、第三方服務吞吐率,等等。
流量突增甚至在極端情況下可以產生脈沖流量。脈沖流量是指瞬間發生的超高流量,超出了日常流量峰值的好幾倍甚至是幾十、幾百倍。流量突增的原因通常包括:
- DDoS 攻擊,尤其是來自于不同地理位置的僵尸網絡;
- 由于部分系統不可用,造成級聯故障傳導,導致從客戶端到服務端內部全鏈路上的大量重試,引起的重試風暴;
- 由于促銷、秒殺、Push 推送或運營活動導致的短時間用戶請求大量涌入;
內部系統承載能力不足可能來自兩方面:
- 容量已不能滿足日益增長的業務需求;
- 由于故障轉移導致的臨時資源不足。這種情況非常常見,鑒于此,很多系統都會設計成 N+1 甚至 N+2 冗余度;
1.8.2.過載解決方案
過載的解決方案包括兩個基本原則:減少流量滲透和增加內部系統承載能力。
所謂減少流量滲透,是指丟棄不必要的流量。常見的做法就是限流操作,針對不健康、異常的流量(如 DDoS)在接入層進行清洗和過濾;針對其他突增的流量,如運營活動、Push 推送或重試導致的請求,通過限流組件來丟棄多余流量,確保傳導到下游的流量符合預期。限流要盡可能靠近調用鏈路的頭部,越靠前效果越佳。
另外,由于重試是造成流量突增的重要原因,我們應該增加系統的動態重試能力,當出現重試風暴時,可以遠程下發指令關閉系統的重試功能。在一些大規模的促銷活動之前,我們也可以提前預估峰值 QPS,決定是否要提前關閉重試。
增加內部系統承載能力,是指容量規劃和擴容。容量規劃通常依賴于壓測的指標情況,根據系統壓力的上限,來合理評估和圈定服務器、數據庫、緩存、消息中間件等各種資源的需求上限,并提前預備好資源配額。
擴容一般包括按計劃內擴容和緊急擴容。日常工作中會我們可以巡檢系統的流量、數據量和容量,當發現當前系統承載能力已不能滿足或即將不能滿足容量需求時,需要執行擴容。緊急擴容通常發生在過載時,這類擴容要求迅速、無差錯,這對系統的彈性伸縮能力要求很高。關于彈性伸縮,后面會單獨說明。
1.9.輪值
Oncall 輪值是面向人員的可靠性措施,利用“人為治理“的思路,為“技術治理”提供有益的補充。Oncall 對在線服務尤其是互聯網業務來說,是必不可少的一個環節。
1.9.1.有效的 Oncall
按照 Oncall 輪值的規模和模式,通常可以劃分為兩種情況:
專業運維團隊:在一個小規模的 IT 企業及業務部門中,通常會設置專業的運維團隊,該團隊對所有系統的運行時狀態進行 7*24 小時無間斷監控和巡檢,發出預警、處理和總結故障。這種方式的好處是各司其職,業務團隊并不需要對運維部分負責,運維團隊也不需要關心業務和開發。
DevOps 文化:隨著企業規模的擴大及各種技術棧成熟度的提升,很多企業不再為各業務線設立獨立的運維團隊,而是奉行 DevOps 文化。簡單理解就是研發和運維的界限開始變得模糊,大部分情況都是,研發團隊同時也需要充當運維的角色。
不管采用哪種方式,都必須秉承幾個基本的 Oncall 原則:
有合理的 Oncall 責任人排班。一般來說,每個人輪值一周的粒度比較恰當,既不會太疲憊,又不至于人員頻繁交接帶來額外成本。
對于 Oncall 責任人來說,應該在輪值周期內減免其他工作事項。比如對研發人員來說,Oncall 的一周內不應該再安排研發任務,這樣有利于提升 Oncall 的專注度;
人員需要有備份。建議每個 Oncall 責任人的背后都應該至少有一個 Backup;
建立良好的 Oncall 規范,保證 Oncall 有章可依;
以下是一個實際的 Oncall 值日規范,供各位讀者參考:
1. 值班目標? 通過告警推送(電話、IM、短信、郵件)、系統巡檢(監控、日志等)等方式,及時發現系統異常并處理;? 接收并處理內部人員或外部用戶報告的線上問題;2. 系統巡檢2.1 巡檢方式系統監控:按照值班報告,對后端的系統進行監控巡檢,并留意告警監控詳見:XXX 系統日志:在必要情況下,需要登錄服務器,觀察系統日志,重點查看異常日志(Exception,Error)服務器詳見:XXX 2.2問題處理發現問題,或執行線上操作,需要及時周知項目組!!禁止私自做線上操作!!當出現以下指標異常時:? 系統QPS過高或過低,超過警戒線? 系統響應時間過高或過低,超過警戒線? 系統錯誤率升高,超過警戒線;導致異常的可能原因有:? 基礎設施:如服務器、系統、網絡、接入層、存儲、消息中間件等故障;? 外部服務:如推薦服務、廣告服務、直播服務等對外依賴的服務故障;? 系統缺陷:系統BUG導致的故障,如功能問題、性能問題;需要采取的措施:? 保留證據,如監控截圖,日志保存,現場信息Dump等;? 對于緊急情況(如影響線上業務),必要情況可執行重啟操作;? 對于非緊急情況,可嘗試定位問題并hotfix處理;? 對于無法處理的問題,需要第一時間聯系owner;復制
1.9.2.Oncall 記錄與故障總結
Oncall 值日生必然會發現、處理線上故障,這就意味著必須記錄和總結故障。故障報告應該有固定的格式規范,便于復盤總結。以下是一個參考 Google SRE 規范而制定的故障報告模板和部分樣例:
1.故障總體描述1.1 故障摘要//簡單描繪故障基本情況2020-07-29日,由于代碼誤操作,將一條測試廣告引入到線上Feed流中; 1.2 開始時間//故障開始時間,精確到分2020-07-29 16:20 1.3 結束時間//故障結束時間,精確到分2020-07-30 08:12 1.4 影響時間//故障持續的時間,精確到分17h52min 1.5 影響范圍//故障的業務影響,如影響多少用戶,影響多少數據,影響XX用戶體驗,影響XX效果日期 展現pv 展現uv 計費點擊(已去重)2020-07-29 96598 20059 16462020-07-30 21741 7511 325累計影響點擊1971人次 1.6 觸發條件//能復現故障的步驟1.Feed流內容自動播放超過X秒,出現“這是一條測試廣告”的內容廣告;2.Feed流點擊內容進入播放頁面,播放超過X秒,出現“這是一條測試廣告”的內容廣告;3.點擊該內容廣告,導流到一個無效的Web頁面; 1.7 根本原因//故障的根本原因,一般有:基礎設施、外部服務、系統缺陷、流程規范等由于測試缺乏數據,開發為配合廣告QA測試,在代碼中寫死Mock數據,上線時忘記刪掉; 1.8 修復措施//故障的解決方案描述去掉Mock數據,上線修復; 1.9 發現途徑//故障的發現方式,一般有:業務報障、報警、主動巡檢等業務報障 2.經驗總結2.1 好的方面//本次故障處理中,做的好的經驗總結定位到問題后,響應及時,修復上線速度較快; 2.2 壞的方面//本次故障處理中,做的不好的經驗教訓1.問題發現不夠及時,等待業務報障才開始處理;2.業務類數據無法觸發告警,自動化用例尚未覆蓋該場景;3.處理問題時,出現一次誤判(時間線里有說明);4.開發代碼自查,以及Peer Code Review不夠充分;5.線上回測不夠充分; 2.3 僥幸的方面//本次故障處理中,僥幸的方面使得損失沒有擴大 3.未來改進措施//針對本次故障需要改進的措施,包括不限于:架構升級優化、系統查漏補缺、加強流程規范、升級監控告警等1.減少不必要的硬編碼來Mock數據,改為利用Mock配置后臺,更安全高效;;2.Mock配置后臺目前在Feed服務中已具備,Q3會推廣到其他10來個系統中,達到80%以上覆蓋率;3.自動化用例增加廣告字段檢測能力,提前發現問題,預計本周五前完成 ;4.應給予研發更多的Code Review時間Buffer,在開發環節發現更多問題;5.QA應充分回測,多做冒煙測試,后端QA也建議增加前端驗證環節,更全面發現問題;6.對代碼Mock,需要增加“//TODO:上線前刪除以下mock代碼”,然后可以通過自動化工具檢查,有這種注釋的代碼不應該通過Code Review; 4.時間線//故障處理流水線,時間精確到分。如:2020-07-22 10:30 系統告警,值班人員開始查看監控2020-07-29 16:20 開發A上線需求 (Merge Request地址)該Merge Request中攜帶一條硬編碼的Mock數據,問題開始發生;2020-07-29 23:07 業務反饋Feed流自動播放及對應的播放頁面,出現“這是一條測試廣告”內容廣告;2020-07-29 23:29 業務將該問題通知到開發和測試團隊;2020-07-29 23:34 值日生B判斷該問題為內容廣告業務方向,由于需求在評審時邏輯是:廣告由播放后臺加載,認為該邏輯可能是播放后臺的問題,等待QA報障(此處存在誤判);2020-07-30 06:40 值日生B進一步思考,認為可能存在后端因素,查了之前的需求,發現實現過程中邏輯有變動。斷定是后端上線引起。2020-07-30 07:00 值日生B抓包分析,發現后端下發恒定的廣告Mock字段,開始查閱29號上線的Merge Request,發現問題代碼;2020-07-30 07:32 值日生B呼叫開發A,簡單溝通原因及修復措施,開發A在路上不能快速上線;2020-07-30 07:43值日生B呼叫開發C,快速溝通問題及修復措施,開發C開始修復上線;2020-07-30 07:51開發C開始發布對Hotfix進行灰度發布;2020-07-30 08:12 上線完畢,出現部分容器資源不足無法更新,和基礎架構同事溝通緊急摘除,系統全部更新完畢;2020-07-30 08:30 經過半小時到一小時的線上檢查,確定問題得以修復;復制
1.10.變更管理
不知道讀者有沒有留意到一個現象,工作日經常會遇到各種系統不穩定:網絡抖動、第三方服務耗時突增、服務器負載突然上升又快速回落,等等。而同樣的現象在節假日尤其是較長的法定節假日反而不容易出現。
經驗表明,90%以上的線上故障基本都是由變更引起的,因此,勢必要高度重視變更帶來的影響。變更不僅僅意味著代碼的改動和發布,也包括容易被忽視的配置變更和數據變更。本章節來討論下這三種變更的管理。
1.10.1.代碼變更
發布無小事。代碼變更是最常見、最頻繁的變化方式,代碼變更應該遵循以下原則:
1.必須要有完備的編碼規范來指導日常開發。包括命名、常量、格式、異常、日志、監控,等等。另外還需要有代碼格式化和代碼檢查插件,自動對代碼進行格式化和規格檢查,未通過檢查的代碼應該不允許提交到遠程倉庫,也不允許發布。
2.必須要有嚴格的 Code Review 規范。可以采用生成 Merge Request 來貫穿于開發、自測、QA 測試、預發布和正式發布環節。Code Review 應該采用技術手段來強制執行,沒有 Merge Request 的代碼變更不應該通過測試,更不應該被線上發布平臺接受。
3.必須要有自動化代碼分析。包括白盒分析(如 SonarQube)和黑盒自動化用例執行。當這些代碼變更的掃描結果不符合預期時,代碼不允許合并到主干,也不允許發布。
4.必須要有上線管理工具,對代碼變更上線進行審批和流程跟蹤,便于將來追溯。
5.必須要采用漸進式方式來發布代碼變更。如常見的預上線(Staging)發布、金絲雀(Canary)發布、藍綠發布等,可以執行一部分灰度流量先上線并觀測指標變化(包括技術指標和業務指標),當指標符合預期時,可以考慮發布剩下的流量。需要注意,全量發布也應該漸進式、滾動式進行,因為即使功能正常工作,也可能會在發布過程中出現性能和可靠性異常。
6.必須要有回滾預案。需要注意的是,回滾盡可能不要重新拉取主干或上一個標簽的代碼并重新打包,一方面會影響回滾速度,另一方面可能發布異常是基礎代碼或打包過程出現問題導致,即使是上一個版本重新多次打包也可能無濟于事,這種情況現實環境中是出現過的。因此,應該有一種基于版本鏡像的回滾機制,即拉取任意版本的包鏡像,直接快速部署,達到本地快速回滾的目的。
1.10.2.配置變更
配置變更一般指配置文件、各種配置后臺、管理后臺中技術參數的配置變更。這些變更幾乎不被人重視,但往往是導致系統故障的罪魁禍首。
筆者的觀點是,任何技術參數的變更,必須要有 Peer Review 機制,即使這些后臺沒有類似 GitHub 的原生 Pull Request 機制,也需要第三方研發人員了解該變更,評估改動風險并執行發布。
1.10.3.數據變更
研發人員不到萬不得已的情況,不要輕易到存儲系統中修改數據。如果確實由于 BUG 導致臟數據,需要批量變更數據,應該采用腳本(SQL 或編程實現)來控制變更的安全性,并且需要第三方研發人員執行 Peer Review。在數據變更的過程中,需要實時監控數據的變化,發現異常需要立即撤銷變更操作。
總結
以上是生活随笔為你收集整理的微服务架构-系统可靠性保障的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: opencv幻灯片代码
- 下一篇: [含论文+开题报告+源码等]SSM家庭理