分享概要 一、業務場景 二、架構演進 三、架構設計 四、穩定性 五、效率 一、業務場景 在開始講解之前,我先為大家介紹一下B站的業務場景。B站的業務大體上可以分為以下幾類: 1、點播類業務 點播類業務就是大家經常看的視頻以及稿件之類相關的業務,這類數據使用場景的特點有: 數據一致性要求較高 耗時敏感 ...
分享概要
一、業務場景
二、架構演進
三、架構設計
四、穩定性
五、效率
一、業務場景
在開始講解之前,我先為大家介紹一下B站的業務場景。B站的業務大體上可以分為以下幾類:
點播類業務就是大家經常看的視頻以及稿件之類相關的業務,這類數據使用場景的特點有:
-
數據一致性要求較高
-
耗時敏感
-
流量大
-
可用性要求高
直播類業務對應B站的S12、跨晚、拜年祭等,有以下幾個特點:
-
數據一致性要求較高
-
熱點數據,如S12的主播房間
-
平時流量中等,大型直播流量會呈現爆炸性增長
-
可用性要求高
-
數據一致性要求較高
-
耗時敏感
-
流量大
-
可用性要求高
如B站本身的會員購,這類業務的要求如下:
-
數據一致性要求較高
-
熱點數據,集中在秒殺場景及熱門番劇
-
平時流量中等,熱門番劇及商品會呈現爆炸性增長
-
可用性要求高
-
數據一致性要求極高
-
可用性要求高
-
流量不大
二、架構演進
介紹完B站的業務場景之後,接下來是B站整體資料庫的架構演進歷史。
1.0階段對於所有互聯網公司而言,其實都有類似的架構——簡單的主從,所有流量集中在一個主庫上。另外,與以前使用的商業資料庫類似場景——單實例多庫。這種架構在公司剛起步的時候是比較方便的,便於業務的快速迭代,但是隨著流量的增長,會出現以下幾個問題:
1)單機的性能瓶頸
伺服器的CPU、記憶體、存儲的限制我們不可能一直垂直升級,從而出現了我們第一個架構演進的小版本——讀寫分離和一主多從,此場景有兩個核心要求:
-
數據一致性要求較低
-
數據敏感度要求較低
滿足以上兩個要求的場景可以很好地規避因MySQL主從複製存在的延遲所帶來的問題,同時又可以滿足業務快速增長帶來的流量壓力。
2)各業務互相影響
隨著業務的發展,各個業務之間的互相影響推動了我們架構的第二個小版本出現——按照業務庫進行遷移拆分。
基於讀寫分離和業務庫維度的拆分還是無法避免各個功能模塊的互相影響。在這種情況下,架構1.0階段的第三個小版本應運而生——基於業務的功能維度進行拆分,將一個X庫拆分為n個庫,拆分完之後分佈在不同的實例。在每個不同的實例下,我們會有不同數量的從庫支撐業務的流量增長,以滿足大部分場景的業務需求。現在B站也有很多業務採用類似的架構,通過進行垂直業務拆分滿足我們的業務增長。
架構2.0階段——水平拆分。成熟、穩定、定製的Proxy是水平拆分的利器,而一個符合要求的Proxy是需要時間進行打磨。為滿足業務的快速發展,我們選擇在業務層實現,也就是我們在代碼層實現路由,雖然配置時會比較繁瑣,但能夠滿足大部分業務場景,很多互聯網公司也有類似的階段。在業務側進行水平拆分之後,我們其實面臨著一個新的問題——跨實例查詢。
1)第一個階段
進入B站演進的3.0階段,我們引入了TiDB,將之前業務層面的分片數據通過TiDB本身的DTS同步到TiDB集群,從而滿足了大部分業務的查詢需求。同時我們在部分場景的業務下直接嘗試使用TiDB。
引入TiDB之後,基於B站的特點,我們對其進行了本地化定製。由於TiDB Server是無狀態的,而官方對於如何路由到每個節點也沒有一個通用的解決方案。因此我們結合 B站的基礎平臺能力,將TiDB Server全部在PaaS上進行容器化,同時把我們的服務發現能力和TiDB Server進行整合,並對相應語言的SDK進行改造,從而實現了TiDB Server的負載均衡,解決了TiDB Server本身的瓶頸,如:故障切換、業務快速感知節點變化、連接數等。
2)第二個階段
到了3.0的第二個階段,我們已經把Proxy打磨為一個很成熟的產品,同時為滿足支撐了異地多活的場景,我們還定製了DTS,把我們資料庫的部署從同城多活直接做到了異地多活,也就是兩地三中心的架構。
首先,在DTS方面,我們也基於B站本身技術棧的特點做了大量的定製,與其它公司開源的組件有部分不同。例如衝突檢測,我們提供了多種可選擇的規則,包括基於特定欄位的以及全欄位匹配的,同時對於衝突欄位數據的R數據處理,我們一般會有兩種途徑:
-
一是直接衝突的場景,將不重要的數據直接打入到我們的隊列里,也就是我們公司之前的Data Bus里;
-
二是業務方可以基於打到Data Bus里的數據做衝突數據處理,通過DTS提供一個介面將數據回寫到特定的機房,因為當需要把數據重新寫入資料庫時,也是需要做防迴環的處理,所以我們DTS上提供一個介面供業務使用。
其次,在主從切換的時候,由於兩地三中心要保證數據可以進行來回切換,切換期間雖然是全局進行,但是一些邊緣場景下仍然會存在數據衝突的問題。所以我們也提供了一個在主從切換下數據衝突以及相關信息的打撈隊列,實現二次處理的功能,這也是我們中間 DTS提供的一個能力。
Proxy的能力與各家主流的功能是類似的,都能夠支持讀寫分離、分庫分表、限流、黑白名單等。對於Proxy的部署,我們採取了兩種方案:
-
一是集中式部署,類似於大家常說的網關模式,能夠便捷地進行統一的限流及資源的調控;
-
二是Sidecar模式,應用層在使用方面比較簡單,直接配置本地IP即可,但是同時已帶來其他問題,如全局的管控(限流、連接等)、成本等。
三、架構設計
接下來為大家介紹的是B站對於不同數據量的場景的架構設計理念。
整體概括起來有以下四種類型:
1)高併發寫入
高併發寫入考驗的是主庫的寫入能力和從庫的複製能力。
2)高併發查詢
高併發查詢一般都會引入緩存的能力,緩存主要涉及以下幾種:
-
分散式緩存主要解決容量的問題;
-
Local Cache在應用層提供能力,在應用本地可以緩存部分數據,但是數據可能存在不及時的問題;
-
多級緩存能夠緩解爆炸性增長的流量帶來的壓力。
3)實時排序
實時排序最直觀的場景就是觀眾在直播間刷禮物的時候展示出來的名次,為保證時效性以及順序,我們一般會採用Redis有序集合。
4)預期外突發流量
預期外突發流量對於我們而言考驗的主要是應用層的快速擴容以及如何對流量進行削峰,同時保證資料庫比較平穩地寫入,也就是非同步寫入的場景。今年最明顯的預期外突發流量場景是佩洛西事件,比我們平常的流量大了將近5倍。
整體上歸納下來有以下幾個特點:
1)秒殺場景
秒殺場景主要涉及合適的選型和請求最簡化。基於公司的基建進行定製,才可以實現最好的性能和體驗。
2)訂單
訂單有很明顯的冷熱數據特征。一般情況下,我們的訂單會被進行一年前、兩年前以及實時訂單的不同拆分。這塊對於資料庫而言考驗的是數據的歸檔及查詢能力。
3)庫存
庫存與秒殺場景存在一定關聯,但並不是完全相關。秒殺場景會涉及到庫存,但是庫存在平常也會一直使用,因此兩者不能進行強掛鉤。
庫存場景主要在於保證減庫存的準確性,以及減少用戶端在訪問時可能存在的衝突,另外是一致性的問題,也就是在秒殺和減庫存時不能出現超賣的情況,避免對商家造成虧本。
4)流量削峰
流量削峰與大型直播賽事遇到的突發流量是不同的,因為這一部分流量是我們已知的,已經預估好會有多少流量,因此我們一般會進行隊列處理以及做分層。
前面介紹了大型直播賽事和電商大促兩個典型場景,我們做了一部分資料庫架構設計以及與應用端的聯動。下麵介紹我們真正進行資料庫架構設計時,需要考慮哪些關鍵點。
首先需要考慮數據,按照我們數據類型的使用場景,我們可以將數據分為以下三種:
1)配置型
配置型類似於我們的數據字典以及一些許可權配置,特點包括:
-
量小
-
幾乎無事務依賴
-
讀多寫少
如果需要對配置型數據進行高併發訪問,只需要加緩存即可,不需要做過多處理。
2)日誌型
日誌型數據包括交易流水、訂單狀態等,我認為日誌型數據也可以稱為流水型數據,特點包括:
-
量大:無法避免,因為我們需要記錄中間各部狀態;
-
無事務依賴:我們後續進行的更多是查詢而很少更改;
-
寫多讀少:讀的比例一般是寫的幾十分之一。
3)狀態型
-
數據量:與業務有關,狀態型數據可以理解為我們的訂單,以及直播場景里刷禮物的扣減情況;
-
事務強依賴:必須保證用戶下單成功之後的庫存扣減,以及用戶給主播打賞之後平臺的扣減和主播收到的禮物;
-
讀多寫多:與用戶的進程掛鉤,寫和讀的場景都比較多。
綜上所述,對於數據一般通過數據量、事務和讀寫請求三個維度進行判斷,從而對數據進行規整和梳理,對比上述我列出的三種數據類型,可以得出數據的特定類型。有了數據類型之後,我們就可以考慮進行下一個階段,即業務對資料庫的要求。
業務對資料庫選型的要求相對而言比較多,包括事務、性能、擴縮容、高可用、遷移。
1)事務
對事務的要求需要基於數據類型進行判斷。
2)性能
一些業務對耗時比較敏感,也就是性能要求比較高,要求必須在多少毫秒以內將數據結果反饋回來。那麼在進行資料庫選型時,我們需要考慮該資料庫能否承載這麼高的性能反應。
3)擴縮容
如果業務要上一個新業務,要考慮滿足一年至兩年的增長的需求,因此資料庫的擴縮容能力非常重要。如果之前申請的數據量比較大,但是業務發展沒有達到預期,那麼資料庫需要縮容,所以這一方面對於資料庫選型也是有要求的。
4)高可用
高可用需要進行取捨,如果要保證數據的強一致性,以及性能的穩定性,必須捨棄一部分東西,具體要與業務溝通和協調,從而保證實際效果符合業務要求。
5)遷移
遷移不僅是業務代碼的改造,從A類資料庫遷到B類資料庫還需要考慮資料庫的遷移成本,以及能否支撐同構和異構。對於業務而言,業務更多考慮的是遷移帶來的業務改造成本,一般業務會比較喜歡協議無變更、基礎操作語法不變的平滑遷移。
資料庫我們要考慮的關鍵點有:
1)事務
如果你想要強事務依賴,可以用傳統型資料庫,以及現有的NewSQL,比如TiDB、OceanBase等。如果不考慮事務,資料庫選擇會更多,比如Redis、MongoDB,主要取決於具體的使用場景和資料庫要承擔的能力。
2)性能
每一種資料庫的性能不同,以關係型資料庫和非關係型資料庫為例,MongoDB和MySQL兩者的性能差別是很大的,依然取決於資料庫要承擔的能力。
3)擴縮容、高可用
擴縮容和高可用不需要進行過多的解釋,因為高可用是DBA選擇資料庫的硬性要求。
4)遷移
這一部分的遷移與業務的遷移存在差異,業務的遷移主要考慮業務改造成本,資料庫的遷移需要考慮以下三點:
-
數據是否一致
-
數據遷移時是否有增量
-
數據遷移會對業務產生什麼影響
如果業務允許直接一刀切,那麼方案則比較簡單;如果業務要求無損,那麼如何評估方案也是需要大家進行考量的。
5)備份/還原
如果可能出現數據需要恢復的場景,則必須考慮備份/還原的能力。我們一般會更傾向於做物理備份,因為物理備份還原比較快,但是一些資料庫沒有提供物理備份的能力,如MongoDB。Redis我們也不會做持續化的備份,因為會導致性能的嚴重下降。
6)容災
容災是第一部分B站資料庫架構演進我們提到的兩地三中心和同城多活需要具備的一個能力。
7)穩定性
資料庫的要求是能夠平穩地對外提供服務,因此穩定性非常關鍵。
8)成本
我們不可能為了保證性能無限地往資料庫裡加機器,因為成本會很高。同時需要考慮開源資料庫和商業資料庫的選擇,在一定程度上商業資料庫的性能比同等規格的開源資料庫更好,但是需要考慮維護成本和二次定製化能力的成本。
9)定製化
商業資料庫有時不會讓我們做更多的定製化開發,但是這會給我們的上下游依賴帶來一個問題,因為大部分場景我們會依賴於類似MySQL的binlog,下游的刷緩存能力以及大數據的實時數倉能力都需要依靠binlog去往下游,也就是CDC能力。那麼這一方面也是資料庫選型需要進行評估的重要能力。
1)多維度綜合考慮
資料庫架構選型並不是從一個維度考慮的,每個資料庫有自身的使用場景和特點,因此資料庫架構選型需要從多個維度綜合考慮,包括數據的維度、業務的真實訴求、DBA團隊能提供的資料庫能力,以及公司對於資料庫的支撐能力,主要是公司其他團隊如開發和平臺類支撐。
2)滿足未來三到五年需求
資料庫架構例如擴縮容能力,必須滿足未來3~5年的需求,而不是頻繁地迭代和更新,否則對業務而言是有損的。
3)穩定為主
資料庫需要平穩運行,而不是天天宕機,因此資料庫架構選型需要以穩定為主。
上圖的右側是目前B站的資料庫團隊使用的資料庫占比,可以看出:
-
Redis、MySQL分別占比第一和第二;
-
占比第三的是MC,因MC無高可用,這一方面需要從業務層進行設計,如MC異常後的回源能力;
-
其他資料庫相對數量較少。
總體來說,B站的資料庫特點是Redis和MySQL為主,其它資料庫主要是基於我們的使用場景進行選擇和提供。
四、穩定性
今天主要是想向大家介紹B站萬億級資料庫選型與架構設計實踐,所以需要考慮資料庫如何提供穩定性能力。
在提供穩定性方面,主要是如何保證資料庫高可用。BRM是我們基於B站的業務特點自研的MySQL高可用組件,在該架構上我們提供了兩個功能節點Leader和Follower,能夠對集群內的所有節點進行管理和探活。不管在哪個節點進行註冊,我們都可以將其註冊到整個集群。因為內部有一個網關會把所有請求轉發到主節點,同時再分發到剩下的Follower節點上。
Leader和Follower都參與投票決策,用以規避因網路抖動問題導致BRM誤判資料庫不可用,然後由Leader節點根據投票結果判斷該節點到底是否宕機。
整體概括起來,我們自研的BRM會有以下六個核心功能:
-
多節點部署:解決MHA單點風險;
-
支持跨機房:跨機房部署解決因網路異常引起的誤切風險;
-
支持權重:B站的資料庫有單機房、同城多活和異地多活,如何保證切到想要的節點上。通過對不同節點設置權重,實現類似MongoDB一樣的基於權重的選主能力;
-
多節點投票決策:通過多個BRM節點對同一個實例探測,滿足多數節點一致才判定實例不可用;
-
專線抖動誤切預防:通過多機房多節點部署我們可以預防因專線抖動導致的主節點誤切,也可以避免跨機房專線異常造成的誤判;
-
熔斷機制:如果出現機房宕機的情況,我們可以先切一部分,查看故障發生的原因,確認沒有問題之後再把熔斷機制放開。
保證系統的平穩運行,也涉及到預警的能力。對於資料庫的預警,真正比較具有可預測性和可觀察性的是慢查詢。資料庫的CPU和IO之類的也可以作為參考,但是會存在一定的誤判,所以我們的方案是針對慢查詢,並且做了一套慢查詢預警體系。
首先對於DB層的慢查詢,我們做了流式的採集上報和實時分析。在實時分析之後,可能會存在誤報的情況,因為如果集群在常態情況下,每天固定某個時刻都會出現比如100條慢查詢,那麼此時是否該報,其實這本身是一個業務某個時間點的特定行為,不會影響整體行為,所以需要將其屏蔽。針對這一方面,我們引入多次線性回歸,通過多次線性回歸實現了對偶發性的抖動的過濾,不同業務級別環比倍數、持續性增長(未到閾值倍數,但持續增長或存在)慢查詢的預警,並且基於規則引擎實現自定義處理。
通過對Proxy的大量使用,我們可以實現針對某個資料庫、某個服務、某類SQL指紋進行攔截、限流、熔斷,以阻止某些異常流量打崩數據的場景,也可以做比較輕鬆狀態下的讀寫分離。
我們也可以做多機房路由,將機動架構下的數據流量轉發到主庫,同時能夠動態發現拓撲結構的變化,新增或刪除從庫以及節點的變化都比較易於發現。
同時我們可以去做更精細化的Sidecar模式,從而減少業務技術與能力,通過Sidecar模式使用Proxy,可以滿足大家在大量場景下的能力。
多活是為了保證在一個機房掛掉之後,我們可以有另外的機房支撐這一方面的能力,我前面講到的Proxy、BRM以及DTS等都是用於滿足多活的訴求。通過多活我們可以保證最大能力的冗災,同時對用戶的影響達到最小,當一個機房掛掉之後,影響的用戶可能只有一部分,快速將用戶全部導流到另外一個機房可以為用戶提供平穩的使用體驗。
五、效率
最後是自動化效率的問題,不管是TiDB這種原生的分散式資料庫還是我們基於Proxy和業務層自研的分散式資料庫能力,同時比如Redis這種超大規模集群,我們現在經常會超過Redis本身的上限,因gossip通信機制,如果節點數量過大會導致節點間的心跳請求將帶寬占滿,所以我們的自動化如何提供效率?以下是自動化運維演進的方向:
當前我們仍然處於自動化運維的階段,自動化平臺能力的核心有四個方面,分別是資源管理研發自助、運維操作和風險管理。
自動化運維平臺
資源管理簡單理解就是資源如何進行分配,有多個維度:
-
主機管理;
-
Operator管理:無論是否上k8s都要提供Operator的管理能力;
-
資源池管理:涉及到如何提高機器使用度的問題;
-
資源報表:涉及到賬單能力,通過賬單可以明確告訴業務哪個地方使用不合理,哪個成本可以節省,以及哪個架構可以調整。
日常情況下,研發有很多事情需要做,例如查詢、導入、加欄位以及健康檢查等。資源申請指的是我們辦了一些比較簡單的常規業務,他們可以基於我們前面講到的策略進行匹配後選擇資料庫。到DBA審核的時候,我們會評估他們寫入的內容是否合理,保證不會出現由於架構設計失敗引發重構的問題。
集群管理、實例管理和數據管理是一些比較日常的運維操作,整體上由平臺化進行支撐,大部分可以通過自動化解決,不需要人工進行管理。
風險管理包括監控與告警、健康度報表以及接入信息脫敏和存儲信息脫敏。B站涉及到電商和支付方面,需要對一些數據和用戶信息進行大量的脫敏,通過數據掃描保證數據的合規。
以上就是我們自動化平臺的能力。
Q&A
Q1:異地多活架構下支持同時多寫嗎?怎麼解決寫入衝突的問題?
A1:現在我們做的異地多活架構會提供同時多寫的能力,有兩個維度進行判斷,一個維度是基於特定欄位,特定欄位可以基於實踐也可以基於業務維度,另一個維度是通過全欄位匹配判斷數據是否衝突。如果衝突則需要下游的處理能力,也就是需要業務方判斷,我們是把數據打到DataBus,由業務判斷這一部分數據如何處理。如果確定好之後,我們會提供一個介面,讓業務按照DTS模式寫入到對端資料庫,從而保證數據的迴環複製。
Q2:DTS兩邊寫入時,如果是按規則去寫入,怎麼保證相互同步的延遲性?
A2:真正用到DTS雙向同步的時候,一般是做異地多活,異地多活的前提是單元化,通過單元化可以把流量集中到特定的地方,如果不做單元化會遇到很多問題,包括數據衝突、數據流量來回飄等。流量調度只是其中的一個過程,時間比較短,主要還是需要應用層和上游CDN支持,僅僅通過資料庫層是很難規避的。
Q3:如何解決分散式資料庫的數據分佈問題?存取時如何保證數據均勻分佈?
A3:主要根據分佈數據本身的分配演算法,分佈數據剛纔講到有兩種維度,一種是狹義的,也就是本身資料庫是一個超大集群,不是通過中間件提供的分散式集群,這種資料庫的數據分佈只能依賴資料庫自身提供能力,如果是自研,則需要通過判斷分片鍵是否合適纔能保證數據分佈。但是所有分散式資料庫都難以保證數據完全分佈均勻,因為數據永遠都會存在熱點和非熱點的問題,要求分散式絕對均勻是不現實的,只能達到一個理想狀況。
本文根據王志廣老師在〖deeplus直播:分散式資料庫轉型與運維實踐探討〗線上分享演講內容整理而成。
本文來自博客園,作者:古道輕風,轉載請註明原文鏈接:https://www.cnblogs.com/88223100/p/Practice-in-the-selection-and-architecture-design-of-a-trillion-level-database-in-Bilibili.html