本文由騰訊技術團隊羅國佳分享,原題“微信讀書后臺架構演進之路”,下文有修訂和重新排版。
1、前言
今年是微信讀書上線10周年,后臺技術架構也伴隨著微信讀書的成長經歷了多次迭代與升級。每一次的組件升級與架構突破,在一個運行了10年的系統上落地都不是一件容易的事情,需要破釜沉舟的決心與膽大心細的業務聯動。
微信讀書經過了多年的發展,贏得了良好的用戶口碑,后臺系統的服務質量直接影響著用戶的體驗。團隊多年來始終保持著“小而美”的基因,快速試錯與迭代成為常態。后臺團隊在日常業務開發的同時,需要主動尋求更多架構上的突破,提升后臺服務的可用性、擴展性,以不斷適應業務與團隊的變化。

技術交流:
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點此)
2、整體架構設計
微信讀書是獨立于微信的App,且由于歷史原因,開發及運維環境均存在一定的差異與隔離。因此,微信讀書的后臺服務實現了從接入層到存儲層的一整套完整架構。

架構上分解為典型的接入層、邏輯層和存儲層:
1)接入層:按業務劃分為多個CGI服務,實現了資源隔離。在CGI層面還實現了如路由、頻控、接入層緩存、長連接等。
2)邏輯層:采用WRMesh框架構建了多個微服務,這些微服務按業務場景進行劃分,實現了不同模塊間的解耦。框架也提供了如RPC、路由發現、過載保護、限流頻控、監控上報等能力。
3)存儲層:主要采用PaxosStore存儲用戶數據,分為K-V和K-Table兩種類型,具備高可用、強一致的特性,針對String和Table兩種類型定制了緩存中間件,以適配某些業務場景下對訪問存儲的性能要求。BookStore提供書籍的存儲服務,滿足讀書場景下對書籍的拆章、修改、下載等需要。此外,也不同程度地使用了騰訊云的PaaS存儲服務,以靈活滿足更多場景需要。
具體的業務邏輯不再贅述,下面簡單介紹下微信讀書近幾年在后臺架構上的一些演進。
3、異構服務間調用:RPC框架
微信讀書后臺微服務源于Hikit框架,采用C++開發。該框架誕生于廣研、QQ郵箱年代,在性能、容災、運維、監控層面都經受了線上的考驗,在微信讀書上線初期作為主要框架,支撐了后臺服務長達數年。
隨著微信讀書的發展,越來越多異構的系統發展起來。例如推薦算法系統是獨立部署在TKE上的容器服務,采用GO語言開發,好處是歷史負擔少,運維更加方便、開發更加便捷。
兩套系統同時存在帶來的問題是如何做好服務治理,推薦系統需要頻繁調用后臺基礎模塊獲取用戶數據,必須要有一套完善的路由管理、容災機制,且考慮到是異構服務,開發語言也不相同,如果為每種語言都定制開發一套服務治理框架,代價會非常高。
在這個階段,我們開發了WRMesh框架,采用Sidecar+Business的方式解決這個問題。

Sidecar專注于處理網絡層的邏輯,和Business業務層分開為兩個進程,由WRMesh腳手架生成代碼,上層業務無需感知。
Sidecar集成了Hikit框架中用于服務治理的核心邏輯:通過UnixSocket與Business進行通信,代理Business的所有網絡讀寫。當Business進程中需要發起網絡請求時,由WRMesh生成的Client代碼會自動識別當前是否在mesh環境中,并轉發請求給Sidecar,由Sidecar完成接下來的網絡處理。
因此:Business進程可以由任意語言任意框架開發,只要遵循Sidecar的通信協議,只需要薄薄的一層網絡協議轉換即可接入到Hikit的服務治理框架中。
另外:對于某些有特殊路由邏輯的Client,如KV訪問、Batch請求等,代理轉發并不能滿足要求,因此Sidecar還提供了插件能力集成這些Client邏輯,最大限度為異構Business業務提供原生C++的能力。
隨著WXG容器平臺P6N的建設越來越完善,許多微信的能力也是基于P6N提供,我們也在思考如何逐步遷移到P6N。由于微信讀書后臺運維目前依賴于企微團隊,有獨立于P6N的一套運維體系,我們負責業務和架構開發。
如果要一刀切把所有后臺服務遷移至P6N,將會面臨幾個問題:
1)框架代碼需要重新適配,開發環境和現網環境都有巨大的改造成本。
2)遷移不是一蹴而就,后臺上百個服務在遷移過程中,會存在新舊服務互調的問題,由于運維環境不互通,微服務之間無法完成服務治理,這種互相調用最終只能通過Proxy來轉發,不僅增加了網絡的失敗率,時延增加,最關鍵的是這個過程會讓容災體系大打折扣。
3)存儲模塊的遷移成本和風險巨大,如果不遷移存儲模塊只遷移了邏輯模塊,那勢必又會存在2中的問題,這個過程很難收尾。
考慮到人力成本及投入性價比,我們最終采用了折衷的方案:
1)一方面:我們保留了依賴于企微的運維環境,保障絕大多數現成服務的穩定運行。
2)另一面:對于微信P6N中的服務,我們搭建了比較完善的Proxy層,例如Svrkit代理、WQueue代理等,兩套架構可以方便進行互通,最大限度的在原有基礎上接入微信的新能力。
目前,微信讀書已順利接入如WQueue、FKVOL、SimOL、TFCC等眾多微信的能力。
4、書籍數據中臺的演進
4.1 技術背景
書籍是微信讀書的內容根基,書籍數量的多少、書籍質量的好壞,很大程度上決定了用戶是否選擇微信讀書作為閱讀App。
過去:我們依托閱文集團提供電子書資源,免去了書籍上架前繁瑣的處理流程,包括排版、審校、元信息管理、更新管理等,后臺服務只需要對接閱文API即可方便獲取書籍數據,我們只需要關注書籍在平臺的存儲管理和分發流轉即可。
近幾年:電子書行業的大環境發生變化,一方面,用戶對書籍品類多樣性、內容質量有更高的訴求,另一方面,平臺對成本、版權等行業因素也更為敏感。因此,我們也在積極探索自簽版權,甚至是自出品的模式,嘗試走更多不一樣的道路。從后臺角度而言,從過去單一依賴閱文集團API的模式,慢慢轉為開放更多的書籍管理接口,形成書籍數據中臺模式,為上層運營同學搭建內容管理平臺,讓更多人可以方便參與到電子書的制作、排版、上下架、運營管理當中。
以EPUB為例,從內容產出到上架到微信讀書,大致經歷以下階段:
1)排版審校:這個階段多為人工或者部分機器自動化介入。
2)上架預處理:這個階段需要創建書籍信息,配置各種運營策略,當這本書是重排版上架時,內容發生改變,由于現網已經存在用戶的劃線筆記、進度等數據,需要有完善指標評估是否適合覆蓋上架,當上架時,需要對用戶數據進行修復,避免發生錯位情況,嚴重影響用戶體驗。
3)EPUB解析:當書籍上架后,由于EPUB是單一文件,不適合解析和管理分發,因此后臺會把源文件解析成自有格式,包括EPUB拆章、圖文分離、樣式分離、按章生成離線包等等。
4)生成BookInfo和BookData并落盤:EPUB文件經過解析后,BookInfo和BookData會存儲到自建的StoreSvr服務上,StoreSvr針對書籍存儲、下載等場景進行了很多優化,具備高可用、低時延的特點,提供了書籍信息獲取、按章下載等核心接口。
4.2 建設數據中臺
回到最初的目標,我們希望把更多的書籍管理能力開放出來,對上層屏蔽電子書底層的后臺邏輯,讓運營同學可以更專注于書籍的管理。
因此,我們構建了如下書籍數據中臺:

后臺服務拆分開StoreAPI和StoreSvr:
1)StoreAPI:提供書籍管理的接口,由運營同學搭建的內容平臺與StoreAPI交互,完成書籍的管理工作;
2)StoreSvr:一方面接受StoreAPI的請求,更新書籍數據,另一方面為現網用戶提供高可用的服務。
StoreAPI提供了如下接口能力:
- 1)書籍id分配、上下架;
- 2)書籍信息創建、修改;
- 3)書籍內容修改、連載更新、訂閱推送;
- 4)運營策略管理。
此外:如上所述,劃線位置和閱讀進度等核心UGC數據由于是按文件偏移記錄,當書籍文件替換后,這些數據會發生錯位,如果不能及時修復,將對用戶體驗造成巨大影響。尤其在一些熱門書籍里,單本書里與位置相關的UGC數據往往能達到億級別,由于文件替換后位置的偏移具有隨機性,并不能采用簡單的映射方式解決,在過去,我們開發了專門的修復服務來完成這個事情,針對每一個UGC內容,采用全文模糊查找的方式重新計算新的偏移,并更新的UGC正排、書籍倒排等多個存儲中。
但隨著用戶數據越來越多,書籍替換頻率越來越頻繁,修復不及時或者失敗的問題逐漸暴露出來:
- 1)修復量大導致修復不及時。過去的修復服務雖然是多機部署,但處理單本書仍只是集中在一臺機器上,單機性能有限;
- 2)修復任務缺乏落盤管理,修復服務一旦重啟,任務丟失。
針對上面的問題:我們重新設計了修復服務,目標是最大限度縮短修復時間,并且讓整個過程是可靠的。
為此,我們先首手考慮業務流程,我們發現在書籍上架前,運營同學本來就需要依賴UGC的修復情況做前置判斷是否覆蓋上架,這個過程中雖然是對UGC抽樣評估,如果能對這個修復映射結果進行緩存,在正式替換文件后,也能一定程度提升修復速度。
在核心修復流程中,我們進行了較大的重構,把單本書的修復任務拆解成多個子任務,存儲在Chubby上,多機器搶鎖共同消費這些任務,由于任務有落盤,在服務上線重啟過程中,也能馬上恢復。修復過程涉及大量的KV寫入,并發太高時容易命中單key的限頻或者版本沖突,我們為此開發了針對K-Str和K-Table的寫入中間件,可以在內存中聚合一批請求進行批量合并寫入,緩解KV層面的失敗。

目前,微信讀書已通過內容平臺完成了多家版權方自簽,并在探索自出品等內容創作新形式。
5、賬號系統的高可用性重構
賬號是微信讀書后臺系統的基石,承擔了登錄、會話密鑰生成與派發、用戶資料管理等核心功能,所有的用戶請求都需經過賬號系統進行鑒權驗證用戶身份,但凡有一點系統抖動都會影響到整個App的正常使用,嚴重者還會導致賬號被踢出無法再次登錄。
賬號系統的架構在微信讀書誕生之初便一直沿用,同一個號段的賬號服務AccountSvr和MySQL部署在同一臺機器上,備機采用主從同步的方式獲取數據,當主機不可用時,備機承擔了所有讀請求。
在某些場景下,為了能使訪問備機時也具備一定的寫入能力,曾經魔改過主備邏輯,但一切都顯得治標不治本,且引入了更復雜的系統特性,整個架構略顯混亂。在機器裁撤、數據擴容過程中,曾造成過幾次嚴重故障,導致App不可用,嚴重影響用戶體驗。究其原因,是因為當時基礎設施還不完善,缺少高性能高可靠的強一致存儲,MySQL也是手動搭建的,運維成本和風險都非常高。
為了徹底解決這個歷史包袱,我們在2024下定決心對其進行重構。重構就意味著要拋棄現有MySQL這套臃腫的存儲方案,把數據遷移到新的存儲組件上。
這里涉及到的挑戰點如下:
- 1)賬號鑒權服務訪問量巨大,遷移過程須盡量不增加系統負擔,且必須是在不停機的情況下進行;
- 2)遷移過程中一旦有數據丟失或者錯誤,會導致用戶資料受損,用戶登錄態丟失,App無法使用;
- 3)賬號系統還涉及用戶id分配和回收邏輯,在切換存儲時如何保證數據的一致性,不重復分配號碼。
背水一戰,沒有退路可言。在經歷了多次論證后,我們決定采用Paxosmemkv作為新的存儲組件,全內存、多副本、強一致的特性,很適合作為賬號系統的底層存儲。
同時,我們為整個遷移過程制定了周密的方案,把每一步進行了分解,且要求每個環節可灰度可回退,同時要做好數據的一致性檢查。
在完成數據遷移后,我們還需要對AccountSvr進行重構,拋棄按號段的賬號分配、路由、緩存邏輯,以全新的視角設計更簡潔的架構。
6、內容召回系統的架構設計
以往微信讀書的搜索僅限于基于書名、作者等維度的文本召回,通過自建的全內存索引服務實現書籍的檢索。全文檢索則基于ES搭建,采用規則分段的方式建立索引,能滿足讀書大部分場景的需要。
在大語言模型迅速發展的近兩年,微信讀書作為一個龐大的內容知識庫,具有大量的書籍原文資源。同時,用戶在微信讀書也留下了大量的文字內容,如書評、想法等,這些內容構成了AI問書的內容基石,也是AI問書區別于其它問答工具的核心優勢。
基于微信讀書構建RAG召回系統,核心挑戰如下:
1)基于書籍原文構建全文檢索,為了達到最好的效果,往往需要支持按語義進行段落切分,在此基礎上構建embedding進行語義召回。微信讀書擁有百萬級書籍原文數據,此外,對于用戶導入書,更是達到億級別規模。現有架構無論從成本還是耗時上都無法解決。
2)為了支持更多維度的召回,需要對UGC內容進行召回,部分UGC內容屬于私密信息,并不向全網公開,只需要滿足用戶個人檢索即可。此時如果用常規的檢索系統構建常駐索引,訪問率太低,成本難以收斂。
為此,我們針對微信讀書不同的RAG使用場景,設計了如下召回架構:

我們把數據劃分成兩類:全局公開可搜以及用戶個人可搜。
1)對于全局公開可搜索的數據:如庫內電子書的全文、書籍大綱、書評、人工知識庫等,我們構建了一套入庫流程,能對源信息進行語義分段、生成正排倒排,語義分段基于開源的chunk模型進行微調,正排基于fkv,倒排則基于ES構建,ES提供了DiskANN方案,通過設置合理的緩存和分片,能在存儲成本和召回效率之間取得不錯的平衡。對于 App 內主搜等低時延場景,為了滿足多種定制化檢索需求,我們自建了基于內存索引的Searchsvr服務,支持索引落盤,可以在毫秒級返回電子書搜索結果。
2)對于用戶個人數據:如導入書全文、個人想法等,特點是數據量大但使用頻率不高,不需要針對全網用戶進行檢索,如果采用上述方案,會帶來成本災難,性價比極低。為此,我們按用戶及物料的維度,基于USearch、Xapian等方案構建了向量及文本索引,這些組件的優勢在于可以把單個索引存儲成文件的形式,便于落盤,配合一些量化的方法,可以把大大壓縮索引大小。在構建索引階段,按用戶+類型構建出不同的索引,并存儲在低成本的COS上,當用戶需要檢索召回時,采用讀時加載的方式實時進行召回,結合CFS進行預熱可以大大提升檢索速度。當檢索完成后,定時淘汰策略會把長期不用的索引從CFS中清理,降低存儲成本。
7、寫在最后
雖然微信讀書已經發展了十個年頭,但我們的腳步從未停止。
在日常業務開發之余,我們也從未停止思考如何讓系統能走得更遠、更穩健,抓住每一個可能的優化點,隨時做好準備,迎接下一個精彩的十年。
8、相關資料
[1] 騰訊資深架構師干貨總結:一文讀懂大型分布式系統設計的方方面面
[3] 子彈短信光鮮的背后:網易云信首席架構師分享億級IM平臺的技術實踐
[4] 知乎技術分享:從單機到2000萬QPS并發的Redis高性能緩存實踐之路
[5] 新手入門:零基礎理解大型分布式架構的演進歷史、技術原理、最佳實踐
[6] 阿里技術分享:深度揭秘阿里數據庫技術方案的10年變遷史
[7] 阿里技術分享:阿里自研金融級數據庫OceanBase的艱辛成長之路
[8] 達達O2O后臺架構演進實踐:從0到4000高并發請求背后的努力
[9] 優秀后端架構師必會知識:史上最全MySQL大表優化方案總結
[10] 小米技術分享:解密小米搶購系統千萬高并發架構的演進和實踐
[11] 一篇讀懂分布式架構下的負載均衡技術:分類、原理、算法、常見方案等
[13] 多維度對比5款主流分布式MQ消息隊列,媽媽再也不擔心我的技術選型了
[14] 從新手到架構師,一篇就夠:從100到1000萬高并發的架構演進之路
[16] 12306搶票帶來的啟示:看我如何用Go實現百萬QPS的秒殺系統(含源碼)
9、微信團隊的其它精華文章
微信團隊原創分享:Android版微信的臃腫之困與模塊化實踐之路
微信異步化改造實踐:8億月活、單機千萬連接背后的后臺解決方案
社交軟件紅包技術解密(十三):微信團隊首次揭秘微信紅包算法,為何你搶到的是0.01元
微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結
IM“掃一掃”功能很好做?看看微信“掃一掃識物”的完整技術實現
微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路
企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等
IM全文檢索技術專題(四):微信iOS端的最新全文檢索技術優化實踐
微信Windows端IM消息數據庫的優化實踐:查詢慢、體積大、文件損壞等
揭秘企業微信是如何支持超大規模IM組織架構的——技術解讀四維關系鏈
微信團隊分享:詳解iOS版微信視頻號直播中因幀率異常導致的功耗問題
微信團隊分享:微信后端海量數據查詢從1000ms降到100ms的技術實踐
微信團隊分享:來看看微信十年前的IM消息收發架構,你做到了嗎
一年擼完百萬行代碼,企業微信的全新鴻蒙NEXT客戶端架構演進之路
(本文已同步發布于:http://www.52im.net/thread-4839-1-1.html)
作者:Jack Jiang (點擊作者姓名進入Github)
出處:http://www.52im.net/space-uid-1.html
交流:歡迎加入即時通訊開發交流群 215891622
討論:http://www.52im.net/
Jack Jiang同時是【原創Java
Swing外觀工程BeautyEye】和【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
本博文
歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。