粉絲與關注,社交好友,都是典型的「多對多關係」的業務,這類業務的核心服務是好友中心,當關系鏈達到百億以後,好友中心架構設計要考慮哪些因素,是本文將要分享的內容。
所謂的「多對多」,來自數據庫設計中的「實體-關係」ER模型,用來描述實體之間的關聯關係,一個學生能夠選修多個課程,一個課程能夠被多個學生選修,這裏學生與課程時間的關係,就是多對多關係。
弱好友關係的創建,不須要雙方彼此贊成
:用戶A關注用戶B,不須要用戶B贊成,此時用戶A與用戶B爲弱好友關係,對A而言,他多「關注」了一我的,對B而言,他多了一個「粉絲」。
強好友關係的創建,須要好友關係雙方彼此贊成
:用戶A請求添加用戶B爲好友,用戶B贊成,此時用戶A與用戶B則互爲強好友關係,即A是B的好友,B也是A的好友。
好友中心是一個典型的多對多業務
,一個用戶能夠添加多個好友,也能夠被多個好友添加。
(1)friend-service:好友中心服務,對調用者提供友好的RPC接口;
服務的接口,不外乎:關注,取關,增長好友,刪除好友,贊成好友申請,不一樣意好友申請。其核心,在於元數據的設計。
經過弱好友關係業務分析,很容易瞭解到,其核心元數據爲:
(1)guanzhu(uid, guanzhu_uid);
(2)fensi(uid, fensi_uid);
(1)guanzhu表,用戶記錄uid全部關注用戶guanzhu_uid;
(2)fensi表,用來記錄uid全部粉絲用戶fensi_uid;
須要強調的是,一條弱關係的產生,會產生兩條記錄,一條關注記錄,一條粉絲記錄。
例如:用戶A(uid=1)關注了用戶B(uid=2),A多關注了一個用戶,B多了一個粉絲,因而:
(1)guanzhu表要插入{1, 2}這一條記錄,1關注了2;
(2)fensi表要插入{2, 1}這一條記錄,2粉了1;
select * from guanzhu where uid=1;
select * from fensi where uid=2;
經過強好友關係業務分析,很容易瞭解到,其核心元數據爲:
uid=1的用戶添加了uid=2的用戶,雙方都贊成加彼此爲好友,強好友關係,在數據庫中應該插入記錄{1, 2}仍是記錄{2,1}呢?
均可以,爲了不歧義,能夠人爲約定,插入記錄時uid1的值必須小於uid2。
例如:有uid=1,2,3三個用戶,他們互爲強好友關係,那邊數據庫中多是這樣的三條記錄:
假設要查詢uid=2的全部好友,只需在uid1和uid2上創建索引,而後:
select * from friend where uid1=2
select * from friend where uid2=2
select * from friend uid1=2 or uid2=2
使用一個表記錄全部關係鏈,若是數據量大了,數據庫進行分庫之後,不久沒法同時知足uid1和uid2上的查詢了麼,此時要怎麼辦呢?
此時,可使用相似於弱關係實現的方案,用數據冗餘的方式,即便分庫後,依然可以知足兩種查詢需求。
(1)guanzhu(uid, guanzhu_uid);
(2)fensi(uid, fensi_uid);
例如:用戶A(uid=1)和用戶B(uid=2)爲強好友關係,即相互關注:
用戶A(uid=1)關注了用戶B(uid=2),A多關注了一個用戶,B多了一個粉絲,因而:
(1)guanzhu表要插入{1, 2}這一條記錄;
同時,用戶B(uid=2)也關注了用戶A(uid=1),B多關注了一個用戶,A多了一個粉絲,因而:
(1)guanzhu表要插入{2, 1}這一條記錄;
強調一下:數據冗餘,是多對多關係,知足不一樣維度的查詢需求,在數據量大時,數據水平切分的經常使用實踐。
第一類
:friend(uid1, uid2)表;
第二類
:數據冗餘guanzhu表與fensi表(後文稱正表T1與反表T2);
在數據量小時,看似無差別,
但數據量大時,只有後者,才能知足兩類查詢需求
:
(1)friend表,數據量大時,若是使用uid1來分庫,那麼uid2上的查詢就須要遍歷多庫;
(2)正表T1與反表T2經過數據冗餘來實現好友關係,{1, 2}{2,1}分別存在於兩表中,故兩個表都使用uid來分庫,均只須要進行一次查詢,就能找到對應的關注與粉絲,而不須要多個庫掃描;
問題轉化爲,T1和T2正反表,如何進行數據冗餘呢?
顧名思義,
由好友中心服務同步寫冗餘數據
,如上圖1-4流程:
(2)數據仍可能不一致,例如第二步寫入T1完成後服務重啓,則數據不會寫入T2;
若是系統對處理時間比較敏感,引出經常使用的第二種方案。
數據的雙寫並再也不由好友中心服務來完成,服務層
異步發出一個消息,經過消息總線發送給一個專門的數據複製服務來寫入冗餘數據
,如上圖1-6流程:
(3)服務向消息總線發送一個異步消息(發出便可,不用等返回,一般很快就能完成);
(1)系統的複雜性增長了,多引入了一個組件(消息總線)和一個服務(專用的數據複製服務);
(2)由於返回業務線數據插入成功時,數據還不必定插入到T2中,所以數據有一個不一致時間窗口(這個窗口很短,最終是一致的);
若是想解除「數據冗餘」對系統的耦合,引出經常使用的第三種方案。
數據的
雙寫再也不由好友中心服務來完成,而是由線下的一個服務或者任務來完成
,如上圖1-6流程:
(1)返回業務線數據插入成功時,數據還不必定插入到T2中,所以數據有一個不一致時間窗口(這個窗口很短,最終是一致的);
(2)數據的一致性依賴於線下服務或者任務的可靠性;
數據冗餘當然可以解決多對多關係的數據庫水平切分問題,但又帶來了新的問題,如何保證正表T1與反表T2的數據一致性呢?
能夠看到,無論哪一種方案,
由於兩步操做不能保證原子性,總有出現數據不一致的可能
,高吞吐分佈式事務是業內還沒有解決的難題,此時的架構優化方向,並非徹底保證數據的一致,而是儘早的發現不一致,並修復不一致。
須要強調的是,
最終一致性
,是高吞吐互聯網業務一致性的經常使用實踐
。
如上圖所示,
線下啓動一個離線的掃描工具,不停的比對正表T1和反表T2,若是發現數據不一致,就進行補償修復。
(1)掃描效率低,會掃描大量的「已經可以保證一致」的數據;
(2)因爲掃描的數據量大,掃描一輪的時間比較長,即數據若是不一致,不一致的時間窗口比較長;
有沒有隻掃描「可能存在不一致可能性」的數據,而不是每次掃描所有數據,以提升效率的優化方法呢?
每次只掃描增量的日誌數據
,就可以極大提升效率,縮短數據不一致的時間窗口,如上圖1-4流程所示:
固然,咱們仍是須要一個離線的掃描工具,不停的比對日誌log1和日誌log2,若是發現數據不一致,就進行補償修復。
(1)線上服務略有修改(代價不高,多寫了2條日誌);
(2)雖然比方法一更實時,但時效性仍是不高,不一致窗口取決於掃描的週期;
此次不是寫日誌了,而是向消息總線發送消息,如上圖1-4流程所示:
此次不是須要一個週期掃描的離線工具了,而是
一個實時訂閱消息的服務不停的收消息。
假設正常狀況下,msg1和msg2的接收時間應該在3s之內,若是檢測服務在收到msg1後沒有收到msg2,就嘗試檢測數據的一致性,不一致時進行補償修復。
however,技術方案自己就是一個投入產出比的折衷,能夠根據業務對一致性的需求程度決定使用哪種方法。
(1)好友業務是一個典型的多對多關係,又分爲強好友與弱好友;
(2)數據冗餘是一個常見的多對多業務數據水平切分實踐;
(4)數據冗餘會帶來一致性問題,高吞吐互聯網業務,要想徹底保證事務一致性很難,常見的實踐是最終一致性;
(5)最終一致性的常見實踐是,儘快找到不一致,並修復數據,常見方案有三種:
新嘗試,視頻講架構數據庫
本文分享自微信公衆號 - 架構師之路(road5858)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。微信