1對多業務,數據庫水平切分架構一次搞定

本文將以“帖子中心”為例,介紹“1對多”類業務,隨著數據量的逐步增大,數據庫性能顯著降低,數據庫水平切分相關的架構實踐:

如何來實施水平切分

水平切分后常見的問題

典型問題的優化思路及實踐


一、什么是1對多關系

所謂的“1對1”,“1對多”,“多對多”,來自數據庫設計中的“實體-關系”ER模型,用來描述實體之間的映射關系。


1對1

一個用戶只有一個登錄名,一個登錄名只對應一個用戶

一個uid對應一個login_name,一個login_name只對應一個uid

這是一個1對1的關系。


1對多

一個用戶可以發多條微博,一條微博只有一個發送者

一個uid對應多個msg_id,一個msg_id只對應一個uid

這是一個1對多的關系。


多對多

一個用戶可以關注多個用戶

一個用戶也可以被多個粉絲關注

這是一個多對多的關系。


二、帖子中心業務分析

帖子中心是一個典型的1對多業務。


一個用戶可以發布多個帖子,一個帖子只對應一個發布者。


任何脫離業務的架構設計都是耍流氓,先來看看帖子中心對應的業務需求。


帖子中心,是一個提供帖子發布/修改/刪除/查看/搜索的服務。


寫操作:

發布(insert)帖子

修改(update)帖子

刪除(delete)帖子


讀操作:

通過tid查詢(select)帖子實體,單行查詢

通過uid查詢(select)用戶發布過的帖子,列表查詢

帖子檢索(search),例如通過時間、標題、內容搜索符合條件的帖子


在數據量較大,并發量較大的時候,通常通過元數據與索引數據分離的架構來滿足不同類型的需求:

架構中的幾個關鍵點:

tiezi-center:帖子服務

tiezi-db:提供元數據存儲

tiezi-search:帖子搜索服務

tiezi-index:提供索引數據存儲

MQ:tiezi-center與tiezi-search通訊媒介,一般不直接使用RPC調用,而是通過MQ對兩個子系統解耦(為何這么解耦,請參見《到底什么時候該使用MQ?》)


其中,tiezi-center和tiezi-search分別滿足兩類不同的讀需求

如上圖所示:

tid和uid上的查詢需求,可以由tiezi-center從元數據讀取并返回

其他類檢索需求,可以由tiezi-search從索引數據檢索并返回


對于寫需求

如上圖所示:

增加,修改,刪除的操作都會從tiezi-center發起

tiezi-center修改元數據

tiezi-center將信息修改通知發送給MQ

tiezi-search從MQ接受修改信息

tiezi-search修改索引數據


tiezi-search,搜索架構不是本文的重點(外置索引架構設計,請參見《100億數據1萬屬性數據架構設計》),后文將重點描述帖子中心元數據這一塊的水平切分設計。


三、帖子中心元數據設計

通過帖子中心業務分析,很容易了解到,其核心元數據為:

Tiezi(tid, uid, time, title, content, …);

其中:

tid為帖子ID,主鍵

uid為用戶ID,發帖人

time, title, content …等為帖子屬性


數據庫設計上,在業務初期,單庫就能滿足元數據存儲要求,其典型的架構設計為:

tiezi-center:帖子中心服務,對調用者提供友好的RPC接口

tiezi-db:對帖子數據進行存儲


在相關字段上建立索引,就能滿足相關業務需求:

帖子記錄查詢,通過tid查詢,約占讀請求量90%

select * from t_tiezi where tid=$tid

帖子列表查詢,通過uid查詢其發布的所有帖子,約占讀請求量10%

select * from t_tiezi where uid=$uid


四、帖子中心水平切分-tid切分法

當數據量越來越大時,需要對帖子數據的存儲進行線性擴展。

既然是帖子中心,并且帖子記錄查詢量占了總請求的90%,很容易想到通過tid字段取模來進行水平切分:

這個方法簡單直接,優點

100%寫請求可以直接定位到庫

90%的讀請求可以直接定位到庫


缺點

一個用戶發布的所有帖子可能會落到不同的庫上,10%的請求通過uid來查詢會比較麻煩

如上圖,一個uid訪問需要遍歷所有庫。


五、帖子中心水平切分-uid切分法

有沒有一種切分方法,確保同一個用戶發布的所有帖子都落在同一個庫上,而在查詢一個用戶發布的所有帖子時,不需要去遍歷所有的庫呢?

:使用uid來分庫可以解決這個問題。


新出現的問題:如果使用uid來分庫,確保了一個用戶的帖子數據落在同一個庫上,那通過tid來查詢,就不知道這個帖子落在哪個庫上了,豈不是還需要遍歷全庫,需要怎么優化呢?

tid的查詢是單行記錄查詢,只要在數據庫(或者緩存)記錄tid到uid的映射關系,就能解決這個問題。


新增一個索引庫:

t_mapping(tid, uid);

這個庫只有兩列,可以承載很多數據

即使數據量過大,索引庫可以利用tid水平切分

這類kv形式的索引結構,可以很好的利用cache優化查詢性能

一旦帖子發布,tid和uid的映射關系就不會發生變化,cache的命中率會非常高


使用uid分庫,并增加索引庫記錄tid到uid的映射關系之后,每當有uid上的查詢:

可以通過uid直接定位到庫。


每當有tid上的查詢:

先查詢索引表,通過tid查詢到對應的uid

再通過uid定位到庫


這個方法的優點

一個用戶發布的所以帖子落在同一個庫上

10%的請求過過uid來查詢列表,可以直接定位到庫

索引表cache命中率非常高,因為tid與uid的映射關系不會變


缺點

90%的tid請求,以及100%的修改請求,不能直接定位到庫,需要先進行一次索引表的查詢,當然這個查詢非常塊,通常在5ms內可以返回

數據插入時需要操作元數據與索引表,可能引發潛在的一致性問題


六、帖子中心水平切分-基因法

有沒有一種方法,既能夠通過uid定位到庫,又不需要建立索引表來進行二次查詢呢,這就是本文要敘述的“1對多”業務分庫最佳實踐,基因法


什么是分庫基因?

通過uid分庫,假設分為16個庫,采用uid%16的方式來進行數據庫路由,這里的uid%16,其本質是uid的最后4個bit決定這行數據落在哪個庫上,這4個bit,就是分庫基因


什么是基因法分庫?

在“1對多”的業務場景,使用“1”分庫,在“多”的數據id生成時,id末端加入分庫基因,就能同時滿足“1”和“多”的分庫查詢需求。

如上圖所示,uid=666的用戶發布了一條帖子(666的二進制表示為:1010011010):

使用uid%16分庫,決定這行數據要插入到哪個庫中

分庫基因是uid的最后4個bit,即1010

在生成tid時,先使用一種分布式ID生成算法生成前60bit(上圖中綠色部分)

將分庫基因加入到tid的最后4個bit(上圖中粉色部分)

拼裝成最終的64bit帖子tid(上圖中藍色部分)

(怎么生成60bit分布式唯一ID,請參見《分布式ID生成算法》)

這般,保證了同一個用戶發布的所有帖子的tid,都落在同一個庫上,tid的最后4個bit都相同,于是:

通過uid%16能夠定位到庫

通過tid%16也能定位到庫


潛在問題一:同一個uid發布的tid落在同一個庫上,會不會出現數據不均衡?

:只要uid是均衡的,每個用戶發布的平均帖子數是均衡的,每個庫的數據就是均衡的。


潛在問題二:最開始分16庫,分庫基因是4bit,未來要擴充成32庫,分庫基因變成了5bit,那怎么辦?

:需要提前做好容量預估,例如事先規劃好5年內數據增長256庫足夠,就提前預留8bit基因。


七、總結

將以“帖子中心”為典型的“1對多”類業務,在架構上,采用元數據與索引數據分離的架構設計方法:

帖子服務,元數據滿足uid和tid的查詢需求

搜索服務,索引數據滿足復雜搜索尋求


對于元數據的存儲,在數據量較大的情況下,有三種常見的切分方法:

tid切分法,按照tid分庫,同一個用戶發布的帖子落在不同的庫上,通過uid來查詢要遍歷所有庫

uid切分法,按照uid分庫,同一個用戶發布的帖子落在同一個庫上,需要通過索引表或者緩存來記錄tid與uid的映射關系,通過tid來查詢時,先查到uid,再通過uid定位庫

基因法,按照uid分庫,在生成tid里加入uid上的分庫基因,保證通過uid和tid都能直接定位到庫

對于1對多的業務場景,分庫架構不再是瓶頸。


轉自:沈劍的微信文章

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容