博客 / 詳情

返回

微信讀書十週年,後台架構的技術演進和實踐總結

本文由騰訊技術團隊羅國佳分享,原題“微信讀書後台架構演進之路”,下文有修訂和重新排版。

1、前言
今年是微信讀書上線10週年,後台技術架構也伴隨着微信讀書的成長經歷了多次迭代與升級。每一次的組件升級與架構突破,在一個運行了10年的系統上落地都不是一件容易的事情,需要破釜沉舟的決心與膽大心細的業務聯動。微信讀書經過了多年的發展,贏得了良好的用户口碑,後台系統的服務質量直接影響着用户的體驗。團隊多年來始終保持着“小而美”的基因,快速試錯與迭代成為常態。後台團隊在日常業務開發的同時,需要主動尋求更多架構上的突破,提升後台服務的可用性、擴展性,以不斷適應業務與團隊的變化。
圖片

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] 騰訊資深架構師乾貨總結:一文讀懂大型分佈式系統設計的方方面面

[2] 快速理解高性能HTTP服務端的負載均衡技術原理

[3] 子彈短信光鮮的背後:網易雲信首席架構師分享億級IM平台的技術實踐

[4] 知乎技術分享:從單機到2000萬QPS併發的Redis高性能緩存實踐之路

[5] 新手入門:零基礎理解大型分佈式架構的演進歷史、技術原理、最佳實踐

[6] 阿里技術分享:深度揭秘阿里數據庫技術方案的10年變遷史

[7] 阿里技術分享:阿里自研金融級數據庫OceanBase的艱辛成長之路

[8] 達達O2O後台架構演進實踐:從0到4000高併發請求背後的努力

[9] 優秀後端架構師必會知識:史上最全MySQL大表優化方案總結

[10] 小米技術分享:解密小米搶購系統千萬高併發架構的演進和實踐

[11] 一篇讀懂分佈式架構下的負載均衡技術:分類、原理、算法、常見方案等

[12] 通俗易懂:如何設計能支撐百萬併發的數據庫架構?

[13] 多維度對比5款主流分佈式MQ消息隊列,媽媽再也不擔心我的技術選型了

[14] 從新手到架構師,一篇就夠:從100到1000萬高併發的架構演進之路

[15] 美團技術分享:深度解密美團的分佈式ID生成算法

[16] 12306搶票帶來的啓示:看我如何用Go實現百萬QPS的秒殺系統(含源碼)

9、微信團隊的其它精華文章
微信後台基於時間序的海量數據冷熱分級架構設計實踐

微信團隊原創分享:Android版微信的臃腫之困與模塊化實踐之路

微信後台團隊:微信後台異步消息隊列的優化升級實踐分享

微信異步化改造實踐:8億月活、單機千萬連接背後的後台解決方案

一份微信後台技術架構的總結性筆記

社交軟件紅包技術解密(十三):微信團隊首次揭秘微信紅包算法,為何你搶到的是0.01元

微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結

IM“掃一掃”功能很好做?看看微信“掃一掃識物”的完整技術實現

微信團隊分享:微信支付代碼重構帶來的移動端軟件架構上的思考

IM開發寶典:史上最全,微信各種功能參數和邏輯規則資料彙總

微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路

企業微信的IM架構設計揭秘:消息模型、萬人羣、已讀回執、消息撤回等

IM全文檢索技術專題(四):微信iOS端的最新全文檢索技術優化實踐

微信團隊分享:微信後台在海量併發請求下是如何做到不崩潰的

微信Windows端IM消息數據庫的優化實踐:查詢慢、體積大、文件損壞等

微信技術分享:揭秘微信後台安全特徵數據倉庫的架構設計

企業微信針對百萬級組織架構的客户端性能優化實踐

揭秘企業微信是如何支持超大規模IM組織架構的——技術解讀四維關係鏈

微信團隊分享:詳解iOS版微信視頻號直播中因幀率異常導致的功耗問題

微信團隊分享:微信後端海量數據查詢從1000ms降到100ms的技術實踐

大型IM工程重構實踐:企業微信Android端的重構之路

IM技術乾貨:假如你來設計微信的羣聊,你該怎麼設計?

微信團隊分享:來看看微信十年前的IM消息收發架構,你做到了嗎

微信後團隊分享:微信後台基於Ray的分佈式AI計算技術實踐

一年擼完百萬行代碼,企業微信的全新鴻蒙NEXT客户端架構演進之路

(本文已同步發佈於:http://www.52im.net/thread-4839-1-1.html)

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.