摘要:來自作者沈劍更多技術分享,盡在微信公眾號技術雜談前言本文將以好友中心為例,介紹多對多類業務,隨著數據量的逐步增大,數據庫性能顯著降低,數據庫水平切分相關的架構實踐。
前言來自 GitChat 作者:沈劍
更多IT技術分享,盡在微信公眾號:GitChat技術雜談
本文將以“好友中心”為例,介紹“多對多”類業務,隨著數據量的逐步增大,數據庫性能顯著降低,數據庫水平切分相關的架構實踐。
一、什么是多對多關系所謂的“多對多”,來自數據庫設計中的“實體-關系”ER模型,用來描述實體之間的關聯關系,一個學生可以選修多個課程,一個課程可以被多個學生選修,這里學生與課程時間的關系,就是多對多關系。
二、好友中心業務分析好友關系主要分為兩類,弱好友關系與強好友關系,兩類都有典型的互聯網產品應用。
弱好友關系的建立,不需要雙方彼此同意:
用戶A關注用戶B,不需要用戶B同意,此時用戶A與用戶B為弱好友關系,對A而言,暫且理解為“關注”;
用戶B關注用戶A,也不需要用戶A同意,此時用戶A與用戶B也為弱好友關系,對A而言,暫且理解為“粉絲”;
微博粉絲是一個典型的弱好友關系應用。
強好友關系的建立,需要好友關系雙方彼此同意:
用戶A請求添加用戶B為好友,用戶B同意,此時用戶A與用戶B則互為強好友關系,即A是B的好友,B也是A的好友。
QQ好友是一個典型的強好友關系應用。
好友中心是一個典型的多對多業務,一個用戶可以添加多個好友,也可以被多個好友添加,其典型架構為:
friend-service:好友中心服務,對調用者提供友好的RPC接口
db:對好友數據進行存儲
三、弱好友關系-元數據簡版實現通過弱好友關系業務分析,很容易了解到,其核心元數據為:
guanzhu(uid, guanzhu_uid);
fensi(uid, fensi_uid);
其中:
guanzhu表,用戶記錄uid所有關注用戶guanzhu_uid
fensi表,用來記錄uid所有粉絲用戶fensi_uid
需要強調的是,一條弱關系的產生,會產生兩條記錄,一條關注記錄,一條粉絲記錄。
例如:用戶A(uid=1)關注了用戶B(uid=2),A多關注了一個用戶,B多了一個粉絲,于是:
guanzhu表要插入{1, 2}這一條記錄,1關注了2
fensi表要插入{2, 1}這一條記錄,2粉了1
四、強好友關系-元數據實現一如何查詢一個用戶關注了誰呢?
回答:在guanzhu的uid上建立索引:
select * from guanzhu where uid=1;
即可得到結果,1關注了2。
如何查詢一個用戶粉了誰呢?
回答:在fensi的uid上建立索引:
select * from fensi where uid=2;
即可得到結果,2粉了1。
通過強好友關系業務分析,很容易了解到,其核心元數據為:
friend(uid1, uid2);
其中:
uid1,強好友關系中一方的uid
uid2,強好友關系中另一方的uid
uid=1的用戶添加了uid=2的用戶,雙方都同意加彼此為好友,這個強好友關系,在數據庫中應該插入記錄{1, 2}還是記錄{2,1 }呢?
回答:都可以,為了避免歧義,可以人為約定,插入記錄時uid1的值必須小于uid2。
例如:有uid=1,2,3三個用戶,他們互為強好友關系,那邊數據庫中可能是這樣的三條記錄
{1, 2}
{2, 3}
{1,3 }
如何查詢一個用戶的好友呢?
回答:假設要查詢uid=2的所有好友,只需在uid1和uid2上建立索引,然后:
select * from friend where uid1=2
union
select * from friend where uid2=2
即可得到結果。
作業:為何不使用這樣的SQL語句呢?
select * from friend uid1=2 or uid2=2
供大家思考。
五、強好友關系-元數據實現二強好友關系是弱好友關系的一個特例,A和B必須互為關注關系(也可以說,同時互為粉絲關系),即也可以使用關注表和粉絲表來實現:
guanzhu(uid, guanzhu_uid);
fensi(uid, fensi_uid);
例如:用戶A(uid=1)和用戶B(uid=2)為強好友關系,即相互關注:
用戶A(uid=1)關注了用戶B(uid=2),A多關注了一個用戶,B多了一個粉絲,于是:
guanzhu表要插入{1, 2}這一條記錄
fensi表要插入{2, 1}這一條記錄
同時,用戶B(uid=2)也關注了用戶A(uid=1),B多關注了一個用戶,A多了一個粉絲,于是:
guanzhu表要插入{2, 1}這一條記錄
fensi表要插入{1, 2}這一條記錄
六、數據冗余是實現多對多關系水平切分的常用實踐對于強好友關系的兩類實現:
friend(uid1, uid2)表
數據冗余guanzhu表與fensi表(后文稱正表T1與反表T2)
在數據量小時,看似無差異,但數據量大時,數據冗余的優勢就體現出來了:
friend表,數據量大時,如果使用uid1來分庫,那么uid2上的查詢就需要遍歷多庫
正表T1與反表T2通過數據冗余來實現好友關系,{1,2}{2,1}分別存在于兩表中,故兩個表都使用uid來分庫,均只需要進行一次查詢,就能找到對應的關注與粉絲,而不需要多個庫掃描
數據冗余,是多對多關系,在數據量大時,數據水平切分的常用實踐。
七、如何進行數據冗余接下來的問題轉化為,好友中心服務如何來進行數據冗余,常見有三種方法。
方法一:服務同步冗余顧名思義,由好友中心服務同步寫冗余數據,如上圖1-4流程:
業務方調用服務,新增數據
服務先插入T1數據
服務再插入T2數據
服務返回業務方新增數據成功
優點:
不復雜,服務層由單次寫,變兩次寫
數據一致性相對較高(因為雙寫成功才返回)
缺點:
請求的處理時間增加(要插入次,時間加倍)
數據仍可能不一致,例如第二步寫入T1完成后服務重啟,則數據不會寫入T2
如果系統對處理時間比較敏感,引出常用的第二種方案
方法二:服務異步冗余數據的雙寫并不再由好友中心服務來完成,服務層異步發出一個消息,通過消息總線發送給一個專門的數據復制服務來寫入冗余數據,如上圖1-6流程:
業務方調用服務,新增數據
服務先插入T1數據
服務向消息總線發送一個異步消息(發出即可,不用等返回,通常很快就能完成)
服務返回業務方新增數據成功
消息總線將消息投遞給數據同步中心
數據同步中心插入T2數據
優點:
請求處理時間短(只插入1次)
缺點:
系統的復雜性增加了,多引入了一個組件(消息總線)和一個服務(專用的數據復制服務)
因為返回業務線數據插入成功時,數據還不一定插入到T2中,因此數據有一個不一致時間窗口(這個窗口很短,最終是一致的)
在消息總線丟失消息時,冗余表數據會不一致
如果想解除“數據冗余”對系統的耦合,引出常用的第三種方案
方法三:線下異步冗余數據的雙寫不再由好友中心服務來完成,而是由線下的一個服務或者任務來完成,如上圖1-6流程:
業務方調用服務,新增數據
服務先插入T1數據
服務返回業務方新增數據成功
數據會被寫入到數據庫的log中
線下服務或者任務讀取數據庫的log
線下服務或者任務插入T2數據
優點:
數據雙寫與業務完全解耦
請求處理時間短(只插入1次)
缺點:
返回業務線數據插入成功時,數據還不一定插入到T2中,因此數據有一個不一致時間窗口(這個窗口很短,最終是一致的)
數據的一致性依賴于線下服務或者任務的可靠性
上述三種方案各有優缺點,可以結合實際情況選取。
數據冗余固然能夠解決多對多關系的數據庫水平切分問題,但又帶來了新的問題,如何保證正表T1與反表T2的數據一致性呢?
八、如何保證數據的一致性上一節的討論可以看到,不管哪種方案,因為兩步操作不能保證原子性,總有出現數據不一致的可能,高吞吐分布式事務是業內尚未解決的難題,此時的架構優化方向,并不是完全保證數據的一致,而是盡早的發現不一致,并修復不一致。
最終一致性,是高吞吐互聯網業務一致性的常用實踐。更具體的,保證數據最終一致性的方案有三種。
方法一:線下掃面正反冗余表全部數據如上圖所示,線下啟動一個離線的掃描工具,不停的比對正表T1和反表T2,如果發現數據不一致,就進行補償修復。
優點:
比較簡單,開發代價小
線上服務無需修改,修復工具與線上服務解耦
缺點:
掃描效率低,會掃描大量的“已經能夠保證一致”的數據
由于掃描的數據量大,掃描一輪的時間比較長,即數據如果不一致,不一致的時間窗口比較長
有沒有只掃描“可能存在不一致可能性”的數據,而不是每次掃描全部數據,以提高效率的優化方法呢?
方法二:線下掃描增量數據每次只掃描增量的日志數據,就能夠極大提高效率,縮短數據不一致的時間窗口,如上圖1-4流程所示:
寫入正表T1
第一步成功后,寫入日志log1
寫入反表T2
第二步成功后,寫入日志log2
當然,我們還是需要一個離線的掃描工具,不停的比對日志log1和日志log2,如果發現數據不一致,就進行補償修復
優點:
雖比方法一復雜,但仍然是比較簡單的
數據掃描效率高,只掃描增量數據
缺點:
線上服務略有修改(代價不高,多寫了2條日志)
雖然比方法一更實時,但時效性還是不高,不一致窗口取決于掃描的周期
有沒有實時檢測一致性并進行修復的方法呢?
方法三:實時線上“消息對”檢測這次不是寫日志了,而是向消息總線發送消息,如上圖1-4流程所示:
寫入正表T1
第一步成功后,發送消息msg1
寫入反表T2
第二步成功后,發送消息msg2
這次不是需要一個周期掃描的離線工具了,而是一個實時訂閱消息的服務不停的收消息。
假設正常情況下,msg1和msg2的接收時間應該在3s以內,如果檢測服務在收到msg1后沒有收到msg2,就嘗試檢測數據的一致性,不一致時進行補償修復
優點:
效率高
實時性高
缺點:
方案比較復雜,上線引入了消息總線這個組件
線下多了一個訂閱總線的檢測服務
however,技術方案本身就是一個投入產出比的折衷,可以根據業務對一致性的需求程度決定使用哪一種方法。
九、總結文字較多,希望盡量記住如下幾點:
好友業務是一個典型的多對多關系,又分為強好友與弱好友 。
數據冗余是一個常見的多對多業務數據水平切分實踐。
冗余數據的常見方案有三種:
服務同步冗余
服務異步冗余
線下異步冗余
數據冗余會帶來一致性問題,高吞吐互聯網業務,要想完全保證事務一致性很難,常見的實踐是最終一致性。
最終一致性的常見實踐是,盡快找到不一致,并修復數據,常見方案有三種。
線下全量掃描法
線下增量掃描法
線上實時檢測法
十、還有哪些未盡事宜以訂單中心為典型的“多KEY”類業務的水平拆分架構又應該怎么處理,敬請期待下期。
彩蛋 【 作者招募 】我們 GitChat 經過半年的運營,在產品形態上不斷改進。
這次,我們將系統性的優化 GitChat 一些內容,在原有 Chat 基礎上推出新的內容分享產品:
GitQ 精品課程
如果您在 IT技術上有自己獨到的學習心得 或 自成體系的技術成長套路,我們非常期待您能在 GitQ 上進一步實現:
GitQ 定位:具備專業性、成體系的IT類課程
GitQ 形態:獨家文章(6~12篇)+讀者圈答疑
GitQ 定價:9.99 / 19.99 等
【作者如何開設 GitQ 精品課?】
提交如下內容:課程名稱 / 用戶定位 / 課程大綱
GitChat 進行內容評估與課程策劃
雙方確定課程細節、交付時間
GitChat 完成課程的上線、宣傳推廣
【作者注意事項】
GitQ 精品課內的文章,在課程上線一年內屬于 GitChat 獨家使用。
按約定時間準時交付文章。
課程上線后,積極在讀者圈回答用戶的提問。
【更多咨詢】
在微信公眾號: GitChat技術雜談(GitChat_Club) 留言 ,或加微信聯系 GitChat 主編:ztx415
實錄:《沈劍:“多對多”類業務數據庫水平切分架構解析》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/11784.html
摘要:來自作者沈劍更多技術分享,盡在微信公眾號技術雜談前言本文將以好友中心為例,介紹多對多類業務,隨著數據量的逐步增大,數據庫性能顯著降低,數據庫水平切分相關的架構實踐。 來自 GitChat 作者:沈劍更多IT技術分享,盡在微信公眾號:GitChat技術雜談 前言 本文將以好友中心為例,介紹多對多類業務,隨著數據量的逐步增大,數據庫性能顯著降低,數據庫水平切分相關的架構實踐。 一、什么是多...
摘要:認為權限授權實際上是的問題。具體的權限,正向授權與負向授權。應用建模業務場景權限管理鑒權設計應用建模系統架構上支撐權限系統靈活配置,不僵硬字段,不僵硬行為,基于各種業務權限管控的特征靈活設計。表示許可權與角色之間多對多的指派關系。 序 之前寫過一篇大話權限中心的PHP架構之道,主要是從軟件工程角度介紹,如何通過編碼規范、依賴管理、數據源架構、事務處理、單元測試等技術,來保障權限系統的高...
摘要:認為權限授權實際上是的問題。具體的權限,正向授權與負向授權。應用建模業務場景權限管理鑒權設計應用建模系統架構上支撐權限系統靈活配置,不僵硬字段,不僵硬行為,基于各種業務權限管控的特征靈活設計。表示許可權與角色之間多對多的指派關系。 序 之前寫過一篇大話權限中心的PHP架構之道,主要是從軟件工程角度介紹,如何通過編碼規范、依賴管理、數據源架構、事務處理、單元測試等技術,來保障權限系統的高...
摘要:中介者模式是用來降低多個對象和類之間的通信復雜性的。系統中對象之間存在復雜的引用關系,產生的相互依賴關系結構混亂且難以理解。同事之間的通信都是通過來協調完成的,承擔了中介者的角色。 本文節選自《設計模式就該這樣學》1 中介者模式的應用場景在現實生活中,中介者的存在是不可缺少的,如果沒有了中介者,我們就不能與遠方...
閱讀 1980·2021-09-26 10:19
閱讀 3249·2021-09-24 10:25
閱讀 1623·2019-12-27 11:39
閱讀 1919·2019-08-30 15:43
閱讀 663·2019-08-29 16:08
閱讀 3504·2019-08-29 16:07
閱讀 902·2019-08-26 11:30
閱讀 1270·2019-08-26 10:41