知乎首頁 Feed 演進

知乎首頁 Feed 演進

來自專欄 Feed 流技術

1. 常用 feed 思路

1.1 維護全局內容列表

  • 無個性化
  • 新內容無法快速展現
  • 固定列表無法調整排序(調整後無法防止拉取重複)

新內容列表疊 基於id偏移 select XX,XX,XX from list offset=XX limit 10

1.2 維護用戶級內容列表

  • 存儲空間大,用戶動態會存在所有粉絲的列表中
  • 固定列表無法調整排序

根據用戶個性化信息, 為每個用戶準備自己的列表

適用頻繁產生新內容的平台,如新聞類。

知乎更多被傳播的是被點贊、關注、收藏等行為標註出來的優質信息。優質信息會被反覆激活,列表涉及重排,進而引入各種問題

1.3 實時生成內容列表

  • 減少空間,減少存儲的重複度
  • 拉取時增加過濾功能,避免了內容重複
  • 生成列表支持演算法排序,為用戶呈現更優質的內容

拉模式,維護信息源,從信息源拉取最新信息,拼裝成列表

2. 知乎首頁基本架構

2.1 拉模式架構思路

  1. 使用 redis.zset 存儲用戶產生的動態 (feed 源)
  2. 計算用戶關注源,拉取動態,merge,過濾,演算法排序,選取最佳 n 條, 拼裝 client 數據

2.2 拉取時過濾掉非法條目

2.3 redis module 機制

載入 module module load lib_path/XX.so

執行定製命令

卸載 module module load module_name_X

3. 首頁 module 的基本功能

3.1 zset 存儲的信息

  • key: source_type,source_id
  • value: item_type,item_id,item_action
  • score: heat_score (當前源的熱度分)

3.2 redis module api 操作 zset

RedisModule_OpenKey(key) # 獲取 zset 中 key 對應 set 的 iteratorRedisModule_ZsetRangeCurrentElement(iterator) # 獲取當前對象RedisModule_ZsetRangePrev(key) # 移動 iterator

3.3 主體邏輯

  • 根據傳入 source 列表,迭代相應 zset
  • 過濾黑名單
  • 多 source 信息 merge

4. 首頁 module 踩過的坑

4.1 module 更新導致 redis 崩潰

  • 增加新命令,臨時打開 core 限制

// RedisModule_CreateCommand("open_core", OpenCoreCommand)int OpenCoreCommand(){ struct rlimit rlp; getrlimit(RLIMIT_CORE, &rlp); rlp.rlim_cur = rlp.rlim_max;}// RedisModule_CreateCommand("close_core", CloseCoreCommand)int CloseCoreCommand(){ struct rlimit rlp; rlp.rlim_cur = 0;}

4.2 dclose 無法 unload module

由於使用了 protobuf 使用 c++11 特性,低版本 GCC 編譯的 so 會被標記為 RTLD_NODELETE

dlopen 參考 Do not unload the library during dlclose(). Consequently, the librarys static variables are not reinitialized if the library is reloaded with dlopen() at a later time.

// dl-lookup.cadd_dependency() { if (undef_map->l_type != lt_loaded || (undef_map->l_flags_1 & DF_1_NODELETE) != 0) map->l_flags_1 |= DF_1_NODELETE;}

解決方案 so 無法 dlclose 問題初探

1. 使用 gcc 5.4.0 及以上版本,編譯後無符號依賴

2. 載入 module 預先載入依賴的符號

// 因為 XXX 依賴 libprotobuf 中不可 close 符號,導致無法 close XXX.sochar *path = "libpath/XXX.so";handle = dlopen(path,RTLD_NOW|RTLD_LOCAL);dlclose(handle); // 失敗// 預先載入 libprotobuf,只 close XXX 可成功 closedlopen("/usr/local/lib/libprotobuf.so.9",RTLD_NOW|RTLD_LOCAL);char *path = "libpath/XXX.so";handle = dlopen(path,RTLD_NOW|RTLD_LOCAL);dlclose(handle); // 成功

推薦閱讀:

右鍵菜單 添加新的 文件對象關聯菜單
0. 簡單的開始。
從模擬電路到計算機軟體
讓你的電腦不在卡
私信回復模板-編程相關

TAG:知乎 | Feed | 計算機 |