參考資料
如何打造千萬級Feed流系統
TableStore Timeline:輕松構建千萬級IM和Feed流系統
Design the Twitter timeline and search
Feed系統架構資料收集
1. 表結構
1.1. Feed 內容庫
內容庫用于存儲用戶發送的消息。
列名 | 是否主鍵 | 說明 |
---|---|---|
user_id | yes | 消息發送者的 id |
message_id | yes | 消息 id,可以用時間戳 |
content | no | 消息內容 |
other | no | 其他信息 |
1.2. 同步表
同步方式,常見的方式有三種:
- 推模式(也叫寫擴散):和名字一樣,就是一種推的方式,發送者發送了一個消息后,立即將這個消息推送給接收者,但是接收者此時不一定在線,那么就需要有一個地方存儲這個數據,這個存儲的地方我們稱為:同步庫。推模式也叫寫擴散的原因是,一個消息需要發送個多個粉絲,那么這條消息就會復制多份,寫放大,所以也叫寫擴散。這種模式下,對同步庫的要求就是寫入能力極強和穩定。讀取的時候因為消息已經發到接收者的收件箱了,只需要讀一次自己的收件箱即可,讀請求的量極小,所以對讀的QPS需求不大。歸納下,推模式中對同步庫的要求只有一個:寫入能力強。
- 拉模式(也叫讀擴散):這種是一種拉的方式,發送者發送了一條消息后,這條消息不會立即推送給粉絲,而是寫入自己的發件箱,當粉絲上線后再去自己關注者的發件箱里面去讀取,一條消息的寫入只有一次,但是讀取最多會和粉絲數一樣,讀會放大,所以也叫讀擴散。拉模式的讀寫比例剛好和寫擴散相反,那么對系統的要求是:讀取能力強。另外這里還有一個誤區,很多人在最開始設計feed流系統時,首先想到的是拉模式,因為這種和用戶的使用體感是一樣的,但是在系統設計上這種方式有不少痛點,最大的是每個粉絲需要記錄自己上次讀到了關注者的哪條消息,如果有1000個關注者,那么這個人需要記錄1000個位置信息,這個量和關注量成正比的,遠比用戶數要大的多,這里要特別注意,雖然在產品前期數據量少的時候這種方式可以應付,但是量大了后就會事倍功半,得不償失,切記切記。
- 推拉結合模式:推模式在單向關系中,因為存在大V,那么一條消息可能會擴散幾百萬次,但是這些用戶中可能有一半多是僵尸,永遠不會上線,那么就存在資源浪費。而拉模式下,在系統架構上會很復雜,同時需要記錄的位置信息是天量,不好解決,尤其是用戶量多了后會成為第一個故障點。基于此,所以有了推拉結合模式,大部分用戶的消息都是寫擴散,只有大V是讀擴散,這樣既控制了資源浪費,又減少了系統設計復雜度。但是整體設計復雜度還是要比推模式復雜。
用圖表對比:
對比項 | 推模式 | 拉模式 | 推拉結合模式 |
---|---|---|---|
寫放大 | 高 | 無 | 中 |
讀放大 | 無 | 高 | 中 |
用戶讀取延時 | 毫秒 | 秒 | 秒 |
讀寫比例 | 1:99 | 99:1 | ~50:50 |
系統要求 | 寫能力強 | 讀能力強 | 讀寫都適中 |
常見系統 | Tablestore、Bigtable等LSM架構的分布式NoSQL | Redis、memcache等緩存系統或搜索系統(推薦排序場景) | 兩者結合 |
架構復雜度 | 簡單 | 復雜 | 更復雜 |
介紹完同步模式中所有場景和模式后,我們歸納下:
- 如果產品中是雙向關系,那么就采用推模式。
- 如果產品中是單向關系,且用戶數少于1000萬,那么也采用推模式,足夠了。
- 如果產品是單向關系,單用戶數大于1000萬,那么采用推拉結合模式,這時候可以從推模式演進過來,不需要額外重新推翻重做。
- 永遠不要只用拉模式。
- 如果是一個初創企業,先用推模式,快速把系統設計出來,然后讓產品去驗證、迭代,等客戶數大幅上漲到1000萬后,再考慮升級為推拉集合模式。
- 如果是按推薦排序,那么是另外的考慮了,架構會完全不一樣,這個后面專門文章介紹。
同步表的結構如下:
列名 | 是否主鍵 | 說明 |
---|---|---|
user_id | yes | 消息接收者用戶ID |
sequence_id | yes | 消息順序ID,可以使用timestamp + send_user_id,也可以直接使用Tablestore的自增列。 |
sender_id | no | 消息發送者的用戶ID |
message_id | no | store_table中的message_id列的值,也就是消息ID。通過sender_id和message_id可以到store_table中查詢到消息內容 |
other | no | 其他信息 |