B 站千億級點贊系統服務架構設計

本期作者

蘆文超

嗶哩嗶哩資深開發工程師

一、前言

1、什麼是點贊

點贊相信大家都不陌生,在 B 站,點贊是 UP 主們跟粉絲之間的特殊羈絆。B 站的點贊系統提供了對視頻、動態、專欄、評論、彈幕等多種實體維度的點贊、點踩以及其餘配套的數據查詢的能力。

圖片

圖片

圖片

2、點贊服務需要提供哪些系統能力

業務能力:

以 “稿件” 爲例,點贊服務需要提供

平臺能力:

點贊作爲一個與社區實體共存的服務,中臺化、平臺化也是點贊服務需要具備的能力

容災能力:

作爲被用戶強感知的站內功能,需要考慮到各種情況下的系統容災。例如當:

存儲不可用

消息隊列不可用

機房災難

數據同步延遲

當然還有其他比如 下游依賴宕機、點贊消息堆積 以及其他未知問題

3、系統需要承載哪些壓力

1. 流量壓力

全局流量壓力:

全站點贊狀態查詢、點贊數查詢等【讀流量】超過 300k,點贊、點踩等【寫流量】超過 15K

單點流量(熱點)壓力:

熱門事件、稿件等帶來的系統熱點問題,包括 DB 熱點、緩存熱點

2. 數據存儲壓力

3. 面對未知災難

針對前言中提到的點讚的平臺能力、系統壓力與容災,我會在下文中作出更加詳細的介紹。

二、點贊整體系統架構簡介

爲了在提供上述能力的前提下經受住流量、存儲、容災三大壓力,點贊目前的系統實現方式如下:

1、系統架構簡介

圖片

整個點贊服務的系統可以分爲五個部分

1、流量路由層(決定流量應該去往哪個機房)

2、業務網關層(統一鑑權、反黑灰產等統一流量篩選)

3、點贊服務(thumbup-service), 提供統一的 RPC 接口

4、點贊異步任務(thumbup-job)

5、數據層(db、kv、redis)

下文將重點分享下 數據存儲層、點贊服務層(thumbup-service)異步任務層(thumbup-job) 的系統設計

2、三級數據存儲

基本數據模型:

①、第一層存儲:DB 層 - (TiDB)

點贊系統中最爲重要的就是點贊記錄表(likes)和點贊計數表(counts),負責整體數據的持久化保存,以及提供緩存失效時的回源查詢能力。

②、第二層存儲

緩存層 Cache:點贊作爲一個高流量的服務,緩存的設立肯定是必不可少的。點贊系統主要使用的是 CacheAside 模式。這一層緩存主要基於 Redis 緩存:以點贊數用戶點贊列表爲例

  1. 點贊數

圖片

key-value = count:patten:{business_id}:{message_id} - {likes},{disLikes}
用業務ID和該業務下的實體ID作爲緩存的Key,並將點贊數與點踩數拼接起來存儲以及更新
  1. 用戶點贊列表

圖片

key-value = user:likes:patten:{mid}:{business_id} - member(messageID)-score(likeTimestamp)
* 用mid與業務ID作爲key,value則是一個ZSet,member爲被點讚的實體ID,score爲點讚的時間。當改業務下某用戶有新的點贊操作的時候,被點讚的實體則會通過 zadd的方式把最新的點贊記錄加入到該ZSet裏面來
爲了維持用戶點贊列表的長度(不至於無限擴張),需要在每一次加入新的點贊記錄的時候,按照固定長度裁剪用戶的點贊記錄緩存。該設計也就代表用戶的點贊記錄在緩存中是有限制長度的,超過該長度的數據請求需要回源DB查詢

③、第三層存儲

LocalCache - 本地緩存

④、針對 TIDB 海量歷史數據的遷移歸檔

遷移歸檔的原因 (初衷),是爲了減少 TIDB 的存儲容量, 節約成本的同時也多了一層存儲,可以作爲災備數據。

以下是在 KV 數據庫(taishan)中點讚的數據與索引的組織形式:

  1. 點贊記錄
1_{mid}_${business_id}_${type}_${message_id} => {origin_id}_{mtime}
  1. 用戶點贊列表索引

圖片

2_{mid}_${business_id}_${type}_${mtime}_{message_id} => {origin_id}
  1. 實體維度點贊記錄索引

圖片

3_{message_id}_${business_id}_${type}_${mtime}_${mid}=>{origin_id}

3、存儲層的優化和思考

作爲一個典型的大流量基礎服務,點讚的存儲架構需要最大程度上滿足兩個點

①、滿足業務讀寫需求的同時具備最大的可靠性

②、選擇合適的存儲介質與數據存儲形態,最小化存儲成本

從以上兩點觸發,考慮到 KV 數據在業務查詢以及性能上都更契合點讚的業務形態,且 TaiShan 可以水平擴容來滿足業務的增長。點贊服務從當前的關係型數據庫(TiDB)+ 緩存(Redis)逐漸過渡至 KV 型數據庫(Taishan)+ 緩存(Redis),以具備更強的可靠性。

同時 TaiShan 作爲公司自研的 KV 數據庫,在成本上也能更優於使用 TiDB 存儲。

4、點贊服務層(thumbup-service)

作爲面對 C 端流量的直接接口,在提供服務的同時,需要思考在面對各種未知或者可預知的災難時,如何儘可能提供服務

在 DB 的設計上,點贊服務有兩地機房互爲災備,正常情況下,機房 1 承載所有寫流量與部分讀流量,機房 2 承載部分讀流量。當 DB 發生故障時,通過 db-proxy(sidercar)的切換可以將讀寫流量切換至備份機房繼續提供服務。

圖片

圖片

在緩存(Redis)上,點贊服務也擁有兩套處於不同機房的集羣,並且通過異步任務消費 TiDB 的 binLog 維護兩地緩存的一致性。可以在需要時切換機房來保證服務的提供,而不會導致大量的冷數據回源數據庫。

服務的容災與降級

(以點贊數、點贊狀態、點贊列表爲例),點贊作爲一個用戶強交互的社區功能服務,對於災難發生時用戶體驗的保證是放在第一位的。所以針對重點接口,我們都會有兜底的數據作爲返回。

多層數據存儲互爲災備

5、異步任務層(thumbup-job)

首先是最重要的用戶行爲數據(點贊、點踩、取消等)的寫入。搭配對數據庫的限流組件以及消費速度監控,保證數據的寫入不超過數據庫的負荷的同時也不會出現數據堆積造成的 C 數據端查詢延遲問題。

圖片

點贊 job 對 binLog 的容災設計

由於點讚的存儲爲 TiDB, 且數據量較大。在實際生產情況中,binLog 會偶遇數據延遲甚至是斷流的問題。爲了減少 binLog 數據延遲對服務數據的影響。服務做了以下改造。

首先在運維層面、代碼層面都對 binLog 的實時性、是否斷流做了監控

脫離 binlog,由業務層(thumb-service)發送重要的數據信息(點贊數變更、點贊狀態事件)等。當發生數據延遲時,程序會自動同時消費由 thumbup-service 發送的容災消息,繼續向下遊發送。

三、未來規劃

1、點贊服務單元化:要陸續往服務單元化的方向迭代、演進。

2、點贊服務平臺化:在目前的業務接入基礎上增加迭代數據分庫存儲能力,做到服務、數據自定義隔離。

3、點贊業務形態探索:以社區爲基礎,繼續探索通過點贊衍生的業務形態。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/4T_S7nR8-HXJ59IbK4FBWQ