0. 前言
常說的 TimeLine 也就是按照時間序排列用戶的動態,一般分為兩種
- 我的關注頁列表: https://www.zhihu.com/follow —— 我關注的所有人的所有動作以時間序排列在 feed 流里
- 某個人動態列表: https://www.zhihu.com/people/yang-hong-zhi-38/activities —— 被查看的用戶,所有動作以時間序排列在 feed 流里
個人動態頁的實現比較簡單,只要存一個列表,響應請求翻頁就好了;關注頁的實現比較複雜,需要把所有好友的動態合併成一個列表,然後對這個列表進行翻頁。
最簡單的作法:類似於個人動態頁為每個用戶的關注頁存儲一張列表,好友產生動態後,將動態追加到列表中 —— 即推模型。
顯而易見,這種模型最大的問題就是浪費資源:
- 用戶 A 關注了 10000 個活躍用戶,那麼需要為他頻繁的追加列表,自然也會佔用很多存儲,但有可能 A 已經很久不用知乎了……
- 用戶 B 是個大 V, 有 100000 個粉絲,每產生一個動態,需要向這 100000 份存儲 中追加動態。
同時,列表可編輯性比較脆弱:
- 用戶 A 取消關注了用戶 B,需要在 A 的列表中刪除 B 的動態
- 用戶 A 增加關注了用戶 C,需要在 A 的列表中加入 C 的動態,而這種操作的複雜度是恐怖的
所以,一般採用「拉」模型:根據動態發起者組織列表,當用戶請求時,將所有的動作發起者動態 merge 在一起,實時生成 feed 列表 —— 拉模型。細節可參考
楊宏志:知乎首頁 Feed 演進?zhuanlan.zhihu.com
1. 架構現狀
當前的知乎的 TimeLine 是兩個完全不相關的項目,單獨維護關注頁、個人動態頁。基本思路如下:
關注頁項目,通過離線腳本監聽用戶動態 「XX 點贊了 XX 回答」…… 存入 redis 的 zset (以動作發起者維度組織數據:key 即發起者 id,item 為動作內容 "vote_up_answer_XX",score 為動作時間),以維護動態列表。在線部分,獲取請求用戶的關注列表,拿到這些被關注者最近的動態,按時間序 merge 在一起。
關注頁項目,通過離線腳本監聽用戶動態「XX 點贊了 XX 回答」…… 存入 Hbase (總數據大約 40億+,無法使用 mysql 等方式存儲),以維護動態列表。在線部分,獲取請求用戶的關注列表,通過 scan 對 Hbase 進行翻頁。