你好,我是悟空。
一、背景
不用想象一種異常場景了,這就真實發生了:B 站晚上 11 點突然掛了,網站主頁直接報 404。
手機 APP 端資料載入不出來。
23:30 分,B 站做了降級頁面,將 404 頁面跳轉到了比較友好的異常頁面。
但是重新整理下頁面,又會跳轉到 404 頁面。
22:35 主頁可以加載出資料了,但是點選動態
還是會報 502
點選某個視訊,直接報 404。
2021-07-14 02:00 之後 B 站開始逐漸恢復。
二、什麼原因
今日凌晨 2 點,B 站釋出公告稱,昨晚,B 站的部分伺服器機房發生故障,造成無法訪問。技術團隊隨即進行了問題排查和修復,現在服務已經陸續恢復正常。而針對網友傳言的 B 站大樓失火一事,上海消防官博進行了闢謠,B 站大樓並未出現火情。
看來 B 站的高可用並不令我們滿意。接下來我們來探討下什麼是高可用以及跨機房部署的思路。本篇正文內容如下:
三、到底什麼是高可用
經過了 2 個小時,B 站才開始逐漸恢復,那 B 站系統到底算不算高可用呢?
首先高可用是個相對的形容詞。那什麼是高可用呢?
3.1 高可用
高可用性(High Availability,HA)我們已經耳熟能詳,指的時系統具備較高的無故障執行的能力。
B 站針對高可用架構還做過一篇分享:
https://cloud.tencent.com/developer/article/1618923
重點:以後 B 站面試這類題不考,望周知。
常見的高可用的方案就是一主多從,主節點掛了,可以快速
切換到從節點,從節點充當主節點,繼續提供服務。比如 SQL Server 的主從架構,Redis 的主從架構,它們都是為了達到高可用性,即使某臺伺服器宕機了,也能繼續提供服務。
剛剛提到了快速,這是一個定性詞語,那定量
的高可用是怎麼樣的?
3.2 定量分析高可用
有兩個相關的概念需要提及:MTBF 和 MTTR。
MTBF:故障間隔時間,可以理解為從上次故障到這次故障,間隔多久,間隔的越長,系統穩定性越高。
MTTR:故障平均恢復時間,可以理解為突然發生故障了,到系統恢復正常,經歷了多長時間,這個時間越短越好,不然使用者等著急了,會收到很多投訴。
可用性計算公式:MTBF/(MTBF+MTTR)* 100%,就是用故障的間隔時間除以故障間隔時間+故障平均恢復時間的總和。
通常情況下,我們使用幾個九來表示系統的可用性,之前我們專案組的系統要求達到年故障時間不超過 5 分鐘,也就是五個九的標準。
3.3 定量分析 B 站
來反觀下 B 站故障了多久,2021-07-13 23:00 到 2021-07-14 02:00,系統逐漸恢復,如果按照年故障總時間來算的話:B 站故障超過 1 個小時了,只能算達到了三個九的標準。如果按照日故障時間來算,只能達到兩個九的標準,也就是 99% 的高可用性,有點慘...
3.4 一個九和兩個九
非常容易達到,一個正常的線上系統不會每天宕機 15 分鐘吧,不然真用不下去了。
3.5 三個就和四個九
允許故障的時間很短,年故障時間是 1 小時到 8 小時,需要從架構設計、程式碼質量、運維體系、故障處理手冊等入手,其中非常關鍵的一環是運維體系,如果線上出了問題,第一波收到異常通知的肯定是運維團隊,根據問題的嚴重程度,會有不同的運維人員來處理,像 B 站這種大事故,就得運維負責人親自上陣了。
另外在緊急故障發生時,是否可以人工手段降級或者加開關,限制部分功能,也是需要考慮的。之前我遇到過一個問題,二維碼刷卡功能出現故障,辛虧之前做了一個開關,可以將二維碼功能隱藏,如果使用者要使用二維碼刷卡功能,統一引導使用者走線下刷卡功能。
3.6 五個九
年故障時間 5 分鐘以內,這個相當短,即使有強大的運維團隊每天值班也很難在收到異常報警後,5 分鐘內快速恢復,所以只能用自動化運維來解決。也就是伺服器自己來保證系統的容災和自動恢復的能力。
3.7 六個九
這個標準相當苛刻了,年故障時間 32 秒。
針對不同的系統,其實對幾個九也不相同。比如公司內部的員工系統,要求四個九組以,如果是給全國使用者使用,且使用人數很多,比如某寶、某餓,那麼就要求五個九以上了,但是即使是數一數二的電商系統,它裡面也有非核心的業務,其實也可以放寬限制,四個九足以,這個就看各家系統的要求,都是成本、人力、重要程度的權衡考慮。
四、如何做到高可用
高可用的方案也是很常見,故障轉移、超時控制、限流、隔離、熔斷、降級,這裡也做個總結。
也可以看這篇:雙 11 的狂歡,乾了這碗「流量防控」湯
4.1 限流
對請求的流量進行控制, 只放行部分請求
,使服務能夠承擔不超過自己能力的流量壓力。
常見限流演算法有三種:時間視窗、漏桶演算法、令牌桶演算法。
4.1.1 時間視窗
時間視窗又分為固定視窗和滑動視窗。具體原理可以看這篇:東漢末年,他們把「服務雪崩」玩到了極致(乾貨)
固定時間視窗:
原理:固定時間內統計流量總量,超過閥值則限制流量。
缺陷:無法限制短時間之內的集中流量。
滑動視窗原理:
原理:統計的總時間固定,但時間段是滑動的。
缺陷:無法控制流量讓它們更加平滑
時間視窗的原理圖在這裡:
4.1.2 漏桶演算法。
原理:按照一個固定的速率將流量露出到接收端。
缺陷:面對突發流量的時候,採用的解決方式是快取在漏桶中,這樣流量的響應時間就會增長,這就與網際網路業務低延遲的要求不符。
4.1.3 令牌桶演算法
原理:一秒內限制訪問次數為 N 次。每隔 1/N 的時間,往桶內放入一個令牌。分散式環境下,用 Redis 作為令牌桶。原理圖如下:
總結的思維導圖在這裡:
4.2 隔離
- 每個服務看作一個獨立執行的系統,即使某一個系統有問題,也不會影響其他服務。
而常規的方案是使用兩款元件:Sentinel 和 Hystrix。
4.3 故障轉移
故障轉移分為兩種:
- 完全對等節點的故障轉移。節點都是同等性質的。
- 不對等節點的故障轉移。不對等就是主備節點都存在。
對等節點的系統中,所有節點都承擔讀寫流量,並且節點不儲存狀態,每個節點就是另外一個的映象。如果某個節點宕機了,按照負載均衡的權重配置訪問其他節點就可以了。
不對等的系統中,有一個主節點,多個備用節點,可以是熱備(備用節點也在提供線上服務),也可以是冷備(只是備份作用)。如果主節點宕機了,可以被系統檢測到,立即進行主備切換。
而如何檢測主節點宕機,就需要用到分散式 Leader 選舉的演算法,常見的就有 Paxos 和 Raft 演算法,詳細的選舉演算法可以看這兩篇:
4.4 超時控制
超時控制就是模組與模組之間的呼叫需要限制請求的時間,如果請求超時的設定得較長,比如 30 s,那麼當遇到大量請求超時的時候,由於請求執行緒都阻塞在慢請求上,導致很多請求都沒來得及處理,如果持續時間足夠長,就會產生級聯反應,形成雪崩
。
還是以我們最熟悉的下單場景為例:使用者下單了一個商品,客戶端呼叫訂單服務來生成預付款訂單,訂單服務呼叫商品服務檢視下單的哪款商品,商品服務呼叫庫存服務判斷這款商品是否有庫存,如有庫存,則可以生成預付款訂單。
雪崩如何造成的?
- 第一次滾雪球:庫存服務不可用(如響應超時等),庫存服務收到的很多請求都未處理完,庫存服務將無法處理更多請求。
- 第二次滾雪球:因商品服務的請求都在等庫存服務返回結果,導致商品服務呼叫庫存服務的很多請求未處理完,商品服務將無法處理其他請求,導致商品服務不可用
- 第三次滾雪球:因商品服務不可用,訂單服務呼叫商品服務的的其他請求無法處理,導致訂單服務不可用。
- 第四次滾雪球:因訂單服務不可用,客戶端將不能下單,更多客戶將重試下單,將導致更多下單請求不可用。
所以設定合理的超時時間非常重要。具體設定的地方:模組與模組之間、請求資料庫、快取處理、呼叫第三方服務。
4.5 熔斷
關鍵字:斷路保護
。比如 A 服務呼叫 B 服務,由於網路問題或 B 服務宕機了或 B 服務的處理時間長,導致請求的時間超長,如果在一定時間內多次出現這種情況,就可以直接將 B 斷路了(A 不再請求B)。而呼叫 B 服務的請求直接返回降級資料,不必等待 B 服務的執行。因此 B 服務的問題,不會級聯影響到 A 服務。
熔斷的詳細原理可以看這篇:東漢末年,他們把「服務雪崩」玩到了極致(乾貨)
4.6 降級
關鍵字:返回降級資料
。網站處於流量高峰期,伺服器壓力劇增,根據當前業務情況及流量,對一些服務和頁面進行有策略的降級(停止服務,所有的呼叫直接返回降級資料)。以此緩解伺服器資源的壓力,保證核心業務的正常執行,保持了客戶和大部分客戶得到正確的響應。降級資料可以簡單理解為快速返回了一個 false,前端頁面告訴使用者“伺服器當前正忙,請稍後再試。”
- 熔斷和降級的相同點?
- 熔斷和限流都是為了保證叢集大部分服務的可用性和可靠性。防止核心服務崩潰。
- 給終端使用者的感受就是某個功能不可用。
- 熔斷和降級的不同點?
- 熔斷是被呼叫放出現了故障,主動觸發的操作。
- 降級是基於全域性考慮,停止某些正常服務,釋放資源。
五、異地多活
5.1 多機房部署
含義:在不同地域的資料中心(IDC)部署了多套服務,而這些服務又是共享同一份業務資料的,而且他們都可以處理使用者的流量。
某個服務掛了,其他服務隨時切換到其他地域的機房中。
現在服務是多套的,那資料庫是不是也要多套,無非就兩種方案:共用資料庫或不共用。
- 共用一套機房的資料庫。
不共用資料庫。每個機房都有自己的資料庫,資料庫之間做同步。實現起來這個方案更復雜。
不論使用哪種方式,都涉及到跨機房資料傳輸延遲的問題。
- 同地多機房專線,延遲 1ms~3 ms。
- 異地多機房專線,延遲 50 ms 左右。
- 跨國多機房,延遲 200 ms 左右。
5.2 同城雙活
高效能的同城雙活,核心思想就是避免跨機房呼叫:
保證同機房服務呼叫:不同的 PRC(遠端呼叫) 服務,向註冊中心註冊不同的服務組,而 RPC 服務只訂閱同機房的 RPC 服務組,RPC 呼叫只存在於本機房。
保證同機房快取呼叫:查詢快取發生在本機房,如果沒有,則從資料庫載入。快取也是採用主備的方式,資料更新採用多機房更新的方式。
保證同機房資料庫查詢:和快取一樣,讀取本機房的資料庫,同樣採用主備方式。
5.3 異地多活
同城雙活無法做到城市級別的容災。所以需要考慮異地多活。
比如上海的伺服器宕機了,還有重慶的伺服器可以頂上來。但兩地距離不要太近,因為發生自燃災害時有可能會被另外一地波及到。
和同城雙活的核心思想一樣,避免跨機房呼叫。但是因為異地方案中的呼叫延遲遠大於同機房的方案,所以資料同步是一個非常值得探討的點。提供兩種方案:
- 基於儲存系統的主從複製,MySQL 和 Redis 天生就具備。但是資料量很大的情況下,效能是較差的。
- 非同步複製的方式。基於訊息佇列,將資料操作作為一個訊息放到訊息佇列,另外的機房消費這條訊息,操作儲存元件。
5.4 兩地三中心
這個概念也被業界提到過很多次。
兩地:本地和異地。
三中心:本地資料中心、同城資料中心、異地資料中心。
這兩個概念也就是我上面說的同城雙活和異地多活的方式,只是針對的是資料中心。原理如下圖所示:
通過 B 站這件事情,我從中也學到了很多,本篇算是拋磚引玉,歡迎大家留言探討。
作者簡介:悟空,8年一線網際網路開發和架構經驗,用故事講解分散式、架構設計、Java 核心技術。《JVM效能優化實戰》專欄作者,開源了《Spring Cloud 實戰 PassJava》專案,自主開發了一個 PMP 刷題小程式。
我是悟空,努力變強,變身超級賽亞人!
巨人的肩膀:
https://cloud.tencent.com/developer/article/1618923
https://mp.weixin.qq.com/s/Vc4N5RcsN-K45o3VaRT4rA
https://time.geekbang.org/column/article/171115
https://time.geekbang.org/column/article/140763
www.passjava.cn