
繼續答星球水友提問,大資料量,高并發量,好友關系鍊、粉絲關系鍊要如何設計?
什麼是關系鍊業務?關系鍊主要分為兩類,弱好友關系與強好友關系,兩類都有典型的網際網路産品應用。 弱好友關系的建立,不需要雙方彼此同意:
- 使用者A關注使用者B,不需要使用者B同意,此時使用者A與使用者B為弱好友關系,對A而言,暫且了解為“關注”;
- 使用者B關注使用者A,也不需要使用者A同意,此時使用者A與使用者B也為弱好友關系,對A而言,暫且了解為“粉絲”;
idol與fans這類微網誌粉絲關系鍊,是一個典型的弱好友關系應用。 強好友關系的建立,需要好友關系雙方彼此同意:
- 使用者A請求添加使用者B為好友,使用者B同意,此時使用者A與使用者B則互為強好友關系,即A是B的好友,B也是A的好友;
好友關系鍊,是一個典型的強好友關系應用。
好友中心是一個典型的多對多業務:
- 一個使用者可以添加多個好友
- 也可以被多個好友添加
其典型架構為:
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
即可得到結果。
方案二強好友關系是弱好友關系的一個特例,A和B必須互為關注關系(也可以說,同時互為粉絲關系),即也可以使用關注表和粉絲表來實作:
例如:使用者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來分庫,均隻需要進行一次查詢,就能找到對應的關注與粉絲,而不需要多個庫掃描
畫外音:假如有10億關系鍊,必須水準切分。 資料備援,是多對多關系,在資料量大時,資料水準切分的常用實踐。 如何進行資料備援?接下來的問題轉化為,好友中心服務如何來進行資料備援,常見有三種方法。 方法一:服務同步備援
顧名思義,由好友中心服務同步寫備援資料,如上圖1-4流程:
- 業務方調用服務,新增資料
- 服務先插入T1資料
- 服務再插入T2資料
- 服務傳回業務方新增資料成功
優點:
- 不複雜,服務層由單次寫,變兩次寫
- 資料一緻性相對較高(因為雙寫成功才傳回)
缺點:
- 請求的處理時間增加(要插入次,時間加倍)
- 資料仍可能不一緻,例如第二步寫入T1完成後服務重新開機,則資料不會寫入T2
如果系統對處理時間比較敏感,引出常用的第二種方案。
方法二:服務異步備援
資料的雙寫并不再由好友中心服務來完成,服務層異步發出一個消息,通過消息總線發送給一個專門的資料複制服務來寫入備援資料,如上圖1-6流程:
- 服務向消息總線發送一個異步消息(發出即可,不用等傳回,通常很快就能完成)
- 消息總線将消息投遞給資料同步中心
- 資料同步中心插入T2資料
- 請求處理時間短(隻插入1次)
- 系統的複雜性增加了,多引入了一個元件(消息總線)和一個服務(專用的資料複制服務)
- 因為傳回業務線資料插入成功時,資料還不一定插入到T2中,是以資料有一個不一緻時間視窗(這個視窗很短,最終是一緻的)
- 在消息總線丢失消息時,備援表資料會不一緻
如果想解除“資料備援”對系統的耦合,引出常用的第三種方案。
方法三:線下異步備援
資料的雙寫不再由好友中心服務來完成,而是由線下的一個服務或者任務來完成,如上圖1-6流程:
- 資料會被寫入到資料庫的log中
- 線下服務或者任務讀取資料庫的log
- 線下服務或者任務插入T2資料
- 資料雙寫與業務完全解耦
- 傳回業務線資料插入成功時,資料還不一定插入到T2中,是以資料有一個不一緻時間視窗(這個視窗很短,最終是一緻的)
- 資料的一緻性依賴于線下服務或者任務的可靠性
上述三種方案各有優缺點,可以結合實際情況選取。 資料備援固然能夠解決多對多關系的資料庫水準切分問題,但又帶來了新的問題,如何保證正表T1與反表T2的資料一緻性呢?
從上面的讨論可以看到,不管哪種方案,因為兩步操作不能保證原子性,總有出現資料不一緻的可能,高吞吐分布式事務是業内尚未解決的難題,此時的架構優化方向:最終一緻性。并不是完全保證資料的實時一緻,而是盡早的發現不一緻,并修複不一緻。 最終一緻性,是高吞吐網際網路業務一緻性的常用實踐。更具體的,保證資料最終一緻性的常見方案有三種。 方法一:線下掃面正反備援表全部資料
如上圖所示,線下啟動一個離線的掃描工具,不停的比對正表T1和反表T2,如果發現資料不一緻,就進行補償修複。
- 比較簡單,開發代價小
- 線上服務無需修改,修複工具與線上服務解耦
- 掃描效率低,會掃描大量的“已經能夠保證一緻”的資料
- 由于掃描的資料量大,掃描一輪的時間比較長,即資料如果不一緻,不一緻的時間視窗比較長
有沒有隻掃描“可能存在不一緻可能性”的資料,而不是每次掃描全部資料,以提高效率的優化方法呢? 方法二:線下掃描增量資料
每次隻掃描增量的日志資料,就能夠極大提高效率,縮短資料不一緻的時間視窗,如上圖1-4流程所示:
- 寫入正表T1
- 第一步成功後,寫入日志log1
- 寫入反表T2
- 第二步成功後,寫入日志log2
當然,我們還是需要一個離線的掃描工具,不停的比對日志log1和日志log2,如果發現資料不一緻,就進行補償修複
- 雖比方法一複雜,但仍然是比較簡單的
- 資料掃描效率高,隻掃描增量資料
- 線上服務略有修改(代價不高,多寫了2條日志)
- 雖然比方法一更實時,但時效性還是不高,不一緻視窗取決于掃描的周期
有沒有實時檢測一緻性并進行修複的方法呢? 方法三:實時線上“消息對”檢測
這次不是寫日志了,而是向消息總線發送消息,如上圖1-4流程所示:
- 第一步成功後,發送消息msg1
- 第二步成功後,發送消息msg2
這次不是需要一個周期掃描的離線工具了,而是一個實時訂閱消息的服務不停的收消息。假設正常情況下,msg1和msg2的接收時間應該在3s以内,如果檢測服務在收到msg1後沒有收到msg2,就嘗試檢測資料的一緻性,不一緻時進行補償修複
- 效率高
- 實時性高
- 方案比較複雜,上線引入了消息總線這個元件
- 線下多了一個訂閱總線的檢測服務
however,技術方案本身就是一個投入産出比的折衷,可以根據業務對一緻性的需求程度決定使用哪一種方法。 總結
- 關系鍊業務是一個典型的多對多關系,又分為強好友與弱好友
- 資料備援是一個常見的多對多業務資料水準切分實踐
- 備援資料的常見方案有三種 (1)服務同步備援 (2)服務異步備援 (3)線下異步備援
- 資料備援會帶來一緻性問題,高吞吐網際網路業務,要想完全保證事務一緻性很難,常見的實踐是最終一緻性
- 最終一緻性的常見實踐是,盡快找到不一緻,并修複資料,常見方案有三種 (1)線下全量掃描法 (2)線下增量掃描法 (3)線上實時檢測法
希望大家有所啟示,思路比結論重要。
本文轉自“架構師之路”公衆号,58沈劍提供。