B 站崩了,總結下「高可用」和「異地多活」

語言: CN / TW / HK

一、背景

不用想象一種異常場景了,這就真實發生了: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 站針對高可用架構還做過一篇分享:

重點:以後 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 站這件事情,我從中也學到了很多,本篇算是拋磚引玉,歡迎大家留言探討。

巨人的肩膀:

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