B站萬億級資料庫選型與架構設計實踐

陶然陶然發表於2022-11-25

   一、業務場景

  在開始講解之前,我先為大家介紹一下B站的業務場景。B站的業務大體上可以分為以下幾類:

  1、點播類業務

  點播類業務就是大家經常看的影片以及稿件之類相關的業務,這類資料使用場景的特點有:

  資料一致性要求較高

  耗時敏感

  流量大

  可用性要求高

  2、直播類業務

  直播類業務對應B站的S12、跨晚、拜年祭等,有以下幾個特點:

  資料一致性要求較高

  熱點資料,如S12的主播房間

  平時流量中等,大型直播流量會呈現爆炸性增長

  可用性要求高

  3、遊戲類業務

  資料一致性要求較高

  耗時敏感

  流量大

  可用性要求高

  4、電商類業務

  如B站本身的會員購,這類業務的要求如下:

  資料一致性要求較高

  熱點資料,集中在秒殺場景及熱門番劇

  平時流量中等,熱門番劇及商品會呈現爆炸性增長

  可用性要求高

  5、支付類業務

  資料一致性要求極高

  可用性要求高

  流量不大

   二、架構演進

  介紹完B站的業務場景之後,接下來是B站整體資料庫的架構演進歷史。

  1、1.0階段  

  1.0階段對於所有網際網路公司而言,其實都有類似的架構——簡單的主從,所有流量集中在一個主庫上。另外,與以前使用的商業資料庫類似場景——單例項多庫。這種架構在公司剛起步的時候是比較方便的,便於業務的快速迭代,但是隨著流量的增長,會出現以下幾個問題:

  1)單機的效能瓶頸

  伺服器的CPU、記憶體、儲存的限制我們不可能一直垂直升級,從而出現了我們第一個架構演進的小版本——讀寫分離和一主多從,此場景有兩個核心要求:

  資料一致性要求較低

  資料敏感度要求較低

  滿足以上兩個要求的場景可以很好地規避因MySQL主從複製存在的延遲所帶來的問題,同時又可以滿足業務快速增長帶來的流量壓力。

  2)各業務互相影響

  隨著業務的發展,各個業務之間的互相影響推動了我們架構的第二個小版本出現——按照業務庫進行遷移拆分。  

  基於讀寫分離和業務庫維度的拆分還是無法避免各個功能模組的互相影響。在這種情況下,架構1.0階段的第三個小版本應運而生——基於業務的功能維度進行拆分,將一個X庫拆分為n個庫,拆分完之後分佈在不同的例項。在每個不同的例項下,我們會有不同數量的從庫支撐業務的流量增長,以滿足大部分場景的業務需求。現在B站也有很多業務採用類似的架構,透過進行垂直業務拆分滿足我們的業務增長。

  2、2.0階段  

  架構2.0階段——水平拆分。成熟、穩定、定製的Proxy是水平拆分的利器,而一個符合要求的Proxy是需要時間進行打磨。為滿足業務的快速發展,我們選擇在業務層實現,也就是我們在程式碼層實現路由,雖然配置時會比較繁瑣,但能夠滿足大部分業務場景,很多網際網路公司也有類似的階段。在業務側進行水平拆分之後,我們其實面臨著一個新的問題——跨例項查詢。

  3、3.0階段

  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、大型直播活動

  整體概括起來有以下四種型別:

  1)高併發寫入

  高併發寫入考驗的是主庫的寫入能力和從庫的複製能力。

  2)高併發查詢

  高併發查詢一般都會引入快取的能力,快取主要涉及以下幾種:

  分散式快取主要解決容量的問題;

  Local Cache在應用層提供能力,在應用本地可以快取部分資料,但是資料可能存在不及時的問題;

  多級快取能夠緩解爆炸性增長的流量帶來的壓力。

  3)實時排序

  實時排序最直觀的場景就是觀眾在直播間刷禮物的時候展示出來的名次,為保證時效性以及順序,我們一般會採用Redis有序集合。

  4)預期外突發流量

  預期外突發流量對於我們而言考驗的主要是應用層的快速擴容以及如何對流量進行削峰,同時保證資料庫比較平穩地寫入,也就是非同步寫入的場景。今年最明顯的預期外突發流量場景是佩洛西事件,比我們平常的流量大了將近5倍。

  2、電商大促

  整體上歸納下來有以下幾個特點:

  1)秒殺場景

  秒殺場景主要涉及合適的選型和請求最簡化。基於公司的基建進行定製,才可以實現更好的效能和體驗。

  2)訂單

  訂單有很明顯的冷熱資料特徵。一般情況下,我們的訂單會被進行一年前、兩年前以及實時訂單的不同拆分。這塊對於資料庫而言考驗的是資料的歸檔及查詢能力。

  3)庫存

  庫存與秒殺場景存在一定關聯,但並不是完全相關。秒殺場景會涉及到庫存,但是庫存在平常也會一直使用,因此兩者不能進行強掛鉤。

  庫存場景主要在於保證減庫存的準確性,以及減少使用者端在訪問時可能存在的衝突,另外是一致性的問題,也就是在秒殺和減庫存時不能出現超賣的情況,避免對商家造成虧本。

  4)流量削峰

  流量削峰與大型直播賽事遇到的突發流量是不同的,因為這一部分流量是我們已知的,已經預估好會有多少流量,因此我們一般會進行佇列處理以及做分層。

  前面介紹了大型直播賽事和電商大促兩個典型場景,我們做了一部分資料庫架構設計以及與應用端的聯動。下面介紹我們真正進行資料庫架構設計時,需要考慮哪些關鍵點。

  3、資料

  首先需要考慮資料,按照我們資料型別的使用場景,我們可以將資料分為以下三種:

  1)配置型

  配置型類似於我們的資料字典以及一些許可權配置,特點包括:

  量小

  幾乎無事務依賴

  讀多寫少

  如果需要對配置型資料進行高併發訪問,只需要加快取即可,不需要做過多處理。

  2)日誌型

  日誌型資料包括交易流水、訂單狀態等,我認為日誌型資料也可以稱為流水型資料,特點包括:

  量大:無法避免,因為我們需要記錄中間各部狀態;

  無事務依賴:我們後續進行的更多是查詢而很少更改;

  寫多讀少:讀的比例一般是寫的幾十分之一。

  3)狀態型

  資料量:與業務有關,狀態型資料可以理解為我們的訂單,以及直播場景裡刷禮物的扣減情況;

  事務強依賴:必須保證使用者下單成功之後的庫存扣減,以及使用者給主播打賞之後平臺的扣減和主播收到的禮物;

  讀多寫多:與使用者的程式掛鉤,寫和讀的場景都比較多。

  綜上所述,對於資料一般透過資料量、事務和讀寫請求三個維度進行判斷,從而對資料進行規整和梳理,對比上述我列出的三種資料型別,可以得出資料的特定型別。有了資料型別之後,我們就可以考慮進行下一個階段,即業務對資料庫的要求。

  4、業務

  業務對資料庫選型的要求相對而言比較多,包括事務、效能、擴縮容、高可用、遷移。

  1)事務

  對事務的要求需要基於資料型別進行判斷。

  2)效能

  一些業務對耗時比較敏感,也就是效能要求比較高,要求必須在多少毫秒以內將資料結果反饋回來。那麼在進行資料庫選型時,我們需要考慮該資料庫能否承載這麼高的效能反應。

  3)擴縮容

  如果業務要上一個新業務,要考慮滿足一年至兩年的增長的需求,因此資料庫的擴縮容能力非常重要。如果之前申請的資料量比較大,但是業務發展沒有達到預期,那麼資料庫需要縮容,所以這一方面對於資料庫選型也是有要求的。

  4)高可用

  高可用需要進行取捨,如果要保證資料的強一致性,以及效能的穩定性,必須捨棄一部分東西,具體要與業務溝通和協調,從而保證實際效果符合業務要求。

  5)遷移

  遷移不僅是業務程式碼的改造,從A類資料庫遷到B類資料庫還需要考慮資料庫的遷移成本,以及能否支撐同構和異構。對於業務而言,業務更多考慮的是遷移帶來的業務改造成本,一般業務會比較喜歡協議無變更、基礎操作語法不變的平滑遷移。

  5、資料庫

  資料庫我們要考慮的關鍵點有:

  1)事務

  如果你想要強事務依賴,可以用傳統型資料庫,以及現有的NewSQL,比如TiDB、OceanBase等。如果不考慮事務,資料庫選擇會更多,比如Redis、MongoDB,主要取決於具體的使用場景和資料庫要承擔的能力。

  2)效能

  每一種資料庫的效能不同,以關係型資料庫和非關係型資料庫為例,MongoDB和MySQL兩者的效能差別是很大的,依然取決於資料庫要承擔的能力。

  3)擴縮容、高可用

  擴縮容和高可用不需要進行過多的解釋,因為高可用是DBA選擇資料庫的硬性要求。

  4)遷移

  這一部分的遷移與業務的遷移存在差異,業務的遷移主要考慮業務改造成本,資料庫的遷移需要考慮以下三點:

  資料是否一致

  資料遷移時是否有增量

  資料遷移會對業務產生什麼影響

  如果業務允許直接一刀切,那麼方案則比較簡單;如果業務要求無損,那麼如何評估方案也是需要大家進行考量的。

  5)備份/還原

  如果可能出現資料需要恢復的場景,則必須考慮備份/還原的能力。我們一般會更傾向於做物理備份,因為物理備份還原比較快,但是一些資料庫沒有提供物理備份的能力,如MongoDB。Redis我們也不會做持續化的備份,因為會導致效能的嚴重下降。

  6)容災

  容災是第一部分B站資料庫架構演進我們提到的兩地三中心和同城多活需要具備的一個能力。

  7)穩定性

  資料庫的要求是能夠平穩地對外提供服務,因此穩定性非常關鍵。

  8)成本

  我們不可能為了保證效能無限地往資料庫里加機器,因為成本會很高。同時需要考慮開源資料庫和商業資料庫的選擇,在一定程度上商業資料庫的效能比同等規格的開源資料庫更好,但是需要考慮維護成本和二次定製化能力的成本。

  9)定製化

  商業資料庫有時不會讓我們做更多的定製化開發,但是這會給我們的上下游依賴帶來一個問題,因為大部分場景我們會依賴於類似MySQL的binlog,下游的刷快取能力以及大資料的實時數倉能力都需要依靠binlog去往下游,也就是CDC能力。那麼這一方面也是資料庫選型需要進行評估的重要能力。

  6、策略

  1)多維度綜合考慮

  資料庫架構選型並不是從一個維度考慮的,每個資料庫有自身的使用場景和特點,因此資料庫架構選型需要從多個維度綜合考慮,包括資料的維度、業務的真實訴求、DBA團隊能提供的資料庫能力,以及公司對於資料庫的支撐能力,主要是公司其他團隊如開發和平臺類支撐。

  2)滿足未來三到五年需求

  資料庫架構例如擴縮容能力,必須滿足未來3~5年的需求,而不是頻繁地迭代和更新,否則對業務而言是有損的。

  3)穩定為主

  資料庫需要平穩執行,而不是天天當機,因此資料庫架構選型需要以穩定為主。  

  上圖的右側是目前B站的資料庫團隊使用的資料庫佔比,可以看出:

  Redis、MySQL分別佔比第一和第二;

  佔比第三的是MC,因MC無高可用,這一方面需要從業務層進行設計,如MC異常後的回源能力;

  其他資料庫相對數量較少。

  總體來說,B站的資料庫特點是Redis和MySQL為主,其它資料庫主要是基於我們的使用場景進行選擇和提供。

   四、穩定性

  今天主要是想向大家介紹B站萬億級資料庫選型與架構設計實踐,所以需要考慮資料庫如何提供穩定效能力。

  1、高可用  

  在提供穩定性方面,主要是如何保證資料庫高可用。BRM是我們基於B站的業務特點自研的MySQL高可用元件,在該架構上我們提供了兩個功能節點Leader和Follower,能夠對叢集內的所有節點進行管理和探活。不管在哪個節點進行註冊,我們都可以將其註冊到整個叢集。因為內部有一個閘道器會把所有請求轉發到主節點,同時再分發到剩下的Follower節點上。

  Leader和Follower都參與投票決策,用以規避因網路抖動問題導致BRM誤判資料庫不可用,然後由Leader節點根據投票結果判斷該節點到底是否當機。

  整體概括起來,我們自研的BRM會有以下六個核心功能:

  多節點部署:解決MHA單點風險;

  支援跨機房:跨機房部署解決因網路異常引起的誤切風險;

  支援權重:B站的資料庫有單機房、同城多活和異地多活,如何保證切到想要的節點上。透過對不同節點設定權重,實現類似MongoDB一樣的基於權重的選主能力;

  多節點投票決策:透過多個BRM節點對同一個例項探測,滿足多數節點一致才判定例項不可用;

  專線抖動誤切預防:透過多機房多節點部署我們可以預防因專線抖動導致的主節點誤切,也可以避免跨機房專線異常造成的誤判;

  熔斷機制:如果出現機房當機的情況,我們可以先切一部分,檢視故障發生的原因,確認沒有問題之後再把熔斷機制放開。

  2、預警

  保證系統的平穩執行,也涉及到預警的能力。對於資料庫的預警,真正比較具有可預測性和可觀察性的是慢查詢。資料庫的CPU和IO之類的也可以作為參考,但是會存在一定的誤判,所以我們的方案是針對慢查詢,並且做了一套慢查詢預警體系。  

  首先對於DB層的慢查詢,我們做了流式的採集上報和實時分析。在實時分析之後,可能會存在誤報的情況,因為如果叢集在常態情況下,每天固定某個時刻都會出現比如100條慢查詢,那麼此時是否該報,其實這本身是一個業務某個時間點的特定行為,不會影響整體行為,所以需要將其遮蔽。針對這一方面,我們引入多次線性迴歸,透過多次線性迴歸實現了對偶發性的抖動的過濾,不同業務級別環比倍數、持續性增長(未到閾值倍數,但持續增長或存在)慢查詢的預警,並且基於規則引擎實現自定義處理。

  3、Proxy  

  透過對Proxy的大量使用,我們可以實現針對某個資料庫、某個服務、某類SQL指紋進行攔截、限流、熔斷,以阻止某些異常流量打崩資料的場景,也可以做比較輕鬆狀態下的讀寫分離。

  我們也可以做多機房路由,將機動架構下的資料流量轉發到主庫,同時能夠動態發現拓撲結構的變化,新增或刪除從庫以及節點的變化都比較易於發現。

  同時我們可以去做更精細化的Sidecar模式,從而減少業務技術與能力,透過Sidecar模式使用Proxy,可以滿足大家在大量場景下的能力。

  4、多活  

  多活是為了保證在一個機房掛掉之後,我們可以有另外的機房支撐這一方面的能力,我前面講到的Proxy、BRM以及DTS等都是用於滿足多活的訴求。透過多活我們可以保證最大能力的冗災,同時對使用者的影響達到最小,當一個機房掛掉之後,影響的使用者可能只有一部分,快速將使用者全部導流到另外一個機房可以為使用者提供平穩的使用體驗。

   五、效率

  最後是自動化效率的問題,不管是TiDB這種原生的分散式資料庫還是我們基於Proxy和業務層自研的分散式資料庫能力,同時比如Redis這種超大規模叢集,我們現在經常會超過Redis本身的上限,因gossip通訊機制,如果節點數量過大會導致節點間的心跳請求將頻寬佔滿,所以我們的自動化如何提供效率?以下是自動化運維演進的方向:  

  當前我們仍然處於自動化運維的階段,自動化平臺能力的核心有四個方面,分別是資源管理研發自助、運維操作和風險管理。  

  自動化運維平臺

  1、資源管理

  資源管理簡單理解就是資源如何進行分配,有多個維度:

  主機管理;

  Operator管理:無論是否上k8s都要提供Operator的管理能力;

  資源池管理:涉及到如何提高機器使用度的問題;

  資源報表:涉及到賬單能力,透過賬單可以明確告訴業務哪個地方使用不合理,哪個成本可以節省,以及哪個架構可以調整。

  2、研發自助

  日常情況下,研發有很多事情需要做,例如查詢、匯入、加欄位以及健康檢查等。資源申請指的是我們辦了一些比較簡單的常規業務,他們可以基於我們前面講到的策略進行匹配後選擇資料庫。到DBA稽核的時候,我們會評估他們寫入的內容是否合理,保證不會出現由於架構設計失敗引發重構的問題。

  3、運維操作

  叢集管理、例項管理和資料管理是一些比較日常的運維操作,整體上由平臺化進行支撐,大部分可以透過自動化解決,不需要人工進行管理。

  4、風險管理

  風險管理包括監控與告警、健康度報表以及接入資訊脫敏和儲存資訊脫敏。B站涉及到電商和支付方面,需要對一些資料和使用者資訊進行大量的脫敏,透過資料掃描保證資料的合規。

來自 “ dbaplus社群 ”, 原文作者:王志廣;原文連結:http://server.it168.com/a2022/1125/6777/000006777137.shtml,如有侵權,請聯絡管理員刪除。

相關文章