知乎首頁 Feed 演進
來自專欄 Feed 流技術
1. 常用 feed 思路
1.1 維護全局內容列表
- 無個性化
- 新內容無法快速展現
- 固定列表無法調整排序(調整後無法防止拉取重複)
1.2 維護用戶級內容列表
- 存儲空間大,用戶動態會存在所有粉絲的列表中
- 固定列表無法調整排序
適用頻繁產生新內容的平台,如新聞類。
知乎更多被傳播的是被點贊、關注、收藏等行為標註出來的優質信息。優質信息會被反覆激活,列表涉及重排,進而引入各種問題
- 減少空間,減少存儲的重複度
- 拉取時增加過濾功能,避免了內容重複
- 生成列表支持演算法排序,為用戶呈現更優質的內容
2. 知乎首頁基本架構
2.1 拉模式架構思路
- 使用 redis.zset 存儲用戶產生的動態 (feed 源)
- 計算用戶關注源,拉取動態,merge,過濾,演算法排序,選取最佳 n 條, 拼裝 client 數據
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
- 根據傳入 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;}
由於使用了 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;}
// 因為 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. 簡單的開始。
※從模擬電路到計算機軟體
※讓你的電腦不在卡
※私信回復模板-編程相關