您好,登錄后才能下訂單哦!
在任何一家互聯網公司,不管其主營業務是什么,都會有一套自己的賬號體系。賬號既是公司所有業務發展留下的最寶貴資產,它可以用來衡量業務指標,例如日活、月活、留存等,同時也給不同業務線提供了大量潛在用戶,業務可以基于賬號來做用戶畫像,制定各自的發展路徑。因此,賬號服務的重要性不言而喻,同時美團業務飛速發展,對賬號業務的可用性要求也越來越高。本文將分享一些我們在高可用探索中的實踐。
衡量一個系統的可用性有兩個指標:
1. MTBF (Mean Time Between Failure)即平均多長時間不出故障;
2. MTTR (Mean Time To Recovery)即出故障后的平均恢復時間。
通過這兩個指標可以計算出可用性,也就是我們大家比較熟悉的“幾個9”。
每條監控都會根據過去的業務曲線計算出一條基線(見下圖),用來跟當前數據做對比,超出設定的閾值后就會觸發告警。
2. 柔性可用
柔性可用的目的是延長不出故障的時間,當業務依賴的下游服務出故障時不影響自身的核心功能或服務。賬號對上層業務提供的鑒權和查詢服務即核心服務,這些服務的QPS非常高,業務方對服務的可用性要求很高,別說是服務故障,就連任何一點抖動都是不能接受的。對此我們先從整體架構上把服務拆分,其次在服務內對下游依賴做資源隔離,都盡可能的縮小故障發生時的影響范圍。
另外對非關鍵路徑上的服務故障做了降級。例如賬號的一個查詢服務依賴Redis,當Redis抖動的時候服務的可用性也隨之降低,我們通過公司內部另外一套緩存中間件Tair來做Redis的備用存儲,當檢測到Redis已經非常不可用時就切到Tair上。
通過開源組件Hystrix或者我們公司自研的中間件Rhino就能非常方便地解決這類問題,其原理是根據最近一個時間窗口內的失敗率來預測下一個請求需不需要快速失敗,從而自動降級,這些步驟都能在毫秒級完成,相比人工干預的情況提升幾個數量級,因此系統的可用性也會大幅提高。下圖是優化前后的對比圖,可以非常明顯的看到,系統的容錯能力提升了,TP999也能控制在合理范圍內。
對于關鍵路徑上的服務故障我們可以減少其影響的用戶數。比如手機快捷登錄流程里的某個關鍵服務掛了,我們可以在返回的失敗文案上做優化,并且在登錄入口掛小黃條提示,讓用戶主動去其他登錄途徑,這樣對于那些設置過密碼或者綁定了第三方的用戶還有其他選擇。
具體的做法是我們在每個登錄入口都關聯了一個計數器,一旦其中的關鍵節點不可用,就會在受影響的計數器上加1,如果節點恢復,則會減1,每個計數器還分別對應一個標志位,當計數器大于0時,標志位為1,否則標志位為0。我們可以根據當前標志位的值得知登錄入口的可用情況,從而在登錄頁展示不同的提示文案,這些提示文案一共有2^5=32種。
3. 異地多活
除了柔性可用,還有一種思路可以來延長不出故障的時間,那就是做冗余,冗余的越多,系統的故障率就越低,并且是呈指數級降低。不管是機房故障,還是存儲故障,甚至是網絡故障,都能依賴冗余去解決,比如數據庫可以通過增加從庫的方式做冗余,服務層可以通過分布式架構做冗余,但是冗余也會帶來新的問題,比如成本翻倍,復雜性增加,這就要衡量投入產出比。
目前美團的數據中心機房主要在北京上海,各個業務都直接或間接的依賴賬號服務,盡管公司內已有北上專線,但因為專線故障或抖動引發的賬號服務不可用,間接導致的業務損失也不容忽視,我們就開始考慮做跨城的異地冗余,即異地多活。
3.1 方案設計
首先我們調研了業界比較成熟的做法,主流思路是分set化,優點是非常利于擴展,缺點是只能按一個維度劃分。比如按用戶ID取模劃分set,其他的像手機號和郵箱的維度就要做出妥協,尤其是這些維度還有唯一性要求,這就使得數據同步或者修改都增加了復雜度,而且極易出錯,給后續維護帶來困難。考慮到賬號讀多寫少的特性(讀寫比是350:1),我們采用了一主多從的數據庫部署方案,優先解決讀多活的問題。
Redis如果也用一主多從的模式可行嗎?答案是不行,因為Redis主從同步機制會優先嘗試增量同步,當增量同步不成功時,再去嘗試全量同步,一旦專線發生抖動就會把主庫拖垮,并進一步阻塞專線,形成“雪崩效應”。因此兩地的Redis只能是雙主模式,但是這種架構有一個問題,就是我們得自己去解決數據同步的問題,除了保證數據不丟,還要保證數據一致。
另外從用戶進來的每一層路由都要是就近的,因此DNS需要開啟智能解析,SLB要開啟同城策略,RPC已默認就近訪問。
總體上賬號的異地多活遵循以下三個原則:
1. 北上任何一地故障,另一地都可提供完整服務。2. 北上兩地同時對外提供服務,確保服務隨時可用。3. 兩地服務都遵循BASE原則,確保數據最終一致。
最終設計方案如下:
寫并發時數據同步過程如下圖:
我們優化的方向是在緩存加載時不同步,只有在數據庫有更新時才去同步。但是數據更新這個流程里不能再使用delete操作,這樣做有可能使緩存出現臟數據,比如下面這個例子:
從理論變為工程實現的時候還有些需要注意的地方,比如同步消息沒發出去、數據收到后寫失敗了。因此我們還需要一個方法來檢測數據不一致的數量,為了做到這點,我們新建了一個定時任務去scan兩地的數據做對比統計,如果發現有不一致的還能及時修復掉。
項目上線后,我們也取得一些成果,首先性能提升非常明顯,異地的調用平均耗時和TP99、TP999均至少下降80%,并且在一次線上專線故障期間,賬號讀服務對外的可用性并沒有受影響,避免了更大范圍的損失。
總結
服務的高可用需要持續性的投入與維護,比如我們會每月做一次容災演練。高可用也不止體現在某一兩個重點項目上,更多的體現在每個業務開發同學的日常工作里。任何一個小Bug都可能引起一次大的故障,讓你前期所有的努力都付之東流,因此我們的每一行代碼,每一個方案,每一次線上改動都應該是仔細推敲過的。高可用應該成為一種思維方式。最后希望我們能在服務高可用的道路上越走越遠。
本文轉載自美團技術團隊微信公眾號,作者: 堂堂 德鑫 楊正,轉載授權請聯系原創作者(meituantech)!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。