聊聊微信後臺架構
大家好,我是小北。
我知道很多同學對微信後臺很感興趣,所以打算整理一些微信後臺的技術棧,以及架構演進的歷程。
偶爾也會寫點自己在後臺開發時的一些體驗。
下面開始第一篇吧,先給大家介紹下微信早期後臺是如何從 0 到 1 的。
2 個月的開發時間,微信後臺系統經歷了從 0 到 1 的過程。
從小步慢跑到快速成長,經歷了平臺化到走出國門,微信交出的這份優異答卷,解題思路是怎樣的?
作者 | 張文瑞
階段一:從無到有
2011.1.21 微信正式發佈。這一天距離微信項目啓動日約爲 2 個月。
就在這 2 個月裏,微信從無到有,大家可能會好奇這期間微信後臺做的最重要的事情是什麼?
我想應該是以下三件事:
1. 確定了微信的消息模型
微信起初定位是一個通訊工具,作爲通訊工具最核心的功能是收發消息。
微信團隊源於廣硏團隊,消息模型跟郵箱的郵件模型也很有淵源,都是存儲轉發。
微信消息模型
上圖展示了這一消息模型,消息被髮出後,會先在後臺臨時存儲;
爲使接收者能更快接收到消息,會推送消息通知給接收者;
最後客戶端主動到服務器收取消息。
2. 制定了數據同步協議
由於用戶的帳戶、聯繫人和消息等數據都在服務器存儲,如何將數據同步到客戶端就成了很關鍵的問題。
爲簡化協議,我們決定通過一個統一的數據同步協議來同步用戶所有的基礎數據。
最初的方案是客戶端記錄一個本地數據的快照 (Snapshot),需要同步數據時,將 Snapshot 帶到服務器,服務器通過計算 Snapshot 與服務器數據的差異,將差異數據發給客戶端,客戶端再保存差異數據完成同步。
不過這個方案有兩個問題:
-
一是 Snapshot 會隨着客戶端數據的增多變得越來越大,同步時流量開銷大;
-
二是客戶端每次同步都要計算 Snapshot,會帶來額外的性能開銷和實現複雜度。
幾經討論後,方案改爲由服務計算 Snapshot,在客戶端同步數據時跟隨數據一起下發給客戶端,客戶端無需理解 Snapshot,只需存儲起來,在下次數據同步數據時帶上即可。
同時,Snapshot 被設計得非常精簡,是若干個 Key-Value 的組合,Key 代表數據的類型,Value 代表給到客戶端的數據的最新版本號。
Key 有三個,分別代表:帳戶數據、聯繫人和消息。
這個同步協議的一個額外好處是客戶端同步完數據後,不需要額外的 ACK 協議來確認數據收取成功,同樣可以保證不會丟數據:
只要客戶端拿最新的 Snapshot 到服務器做數據同步,服務器即可確認上次數據已經成功同步完成,可以執行後續操作。
例如清除暫存在服務的消息等等。
此後,精簡方案、減少流量開銷、儘量由服務器完成較複雜的業務邏輯、降低客戶端實現的複雜度就作爲重要的指導原則,持續影響着後續的微信設計開發。
記得有個比較經典的案例是:我們在微信 1.2 版實現了羣聊功能,但爲了保證新舊版客戶端間的羣聊體驗,我們通過服務器適配,讓 1.0 版客戶端也能參與羣聊。
3. 定型了後臺架構
微信後臺系統架構
微信後臺使用三層架構:接入層、邏輯層和存儲層
接入層提供接入服務,包括長連接入服務和短連接入服務。
長連接入服務同時支持客戶端主動發起請求和服務器主動發起推送;
短連接入服務則只支持客戶端主動發起請求。
邏輯層包括業務邏輯服務和基礎邏輯服務。
業務邏輯服務封裝了業務邏輯,是後臺提供給微信客戶端調用的 API。
基礎邏輯服務則抽象了更底層和通用的業務邏輯,提供給業務邏輯服務訪問。
存儲層包括數據訪問服務和數據存儲服務。
數據存儲服務通過 MySQL 和 SDB(廣硏早期後臺中廣泛使用的 Key-Table 數據存儲系統) 等底層存儲系統來持久化用戶數據。
數據訪問服務適配並路由數據訪問請求到不同的底層數據存儲服務,面向邏輯層提供結構化的數據服務。
比較特別的是,微信後臺每一種不同類型的數據都使用單獨的數據訪問服務和數據存儲服務,例如帳戶、消息和聯繫人等等都是獨立的。
微信後臺主要使用 C++。後臺服務使用 Svrkit 框架搭建,服務之間通過同步 RPC 進行通訊。
Svrkit 框架
(小北:Svrkit 框架就是日常開發最常使用的
Svrkit 是另一個廣硏後臺就已經存在的高性能 RPC 框架,當時尚未廣泛使用,但在微信後臺卻大放異彩。
作爲微信後臺基礎設施中最重要的一部分,Svrkit 這幾年一直不斷在進化。我們使用 Svrkit 構建了數以千計的服務模塊,提供數萬個服務接口,每天 RPC 調用次數達幾十萬億次。
這三件事影響深遠,乃至於 5 年後的今天,我們仍繼續沿用最初的架構和協議,甚至還可以支持當初 1.0 版的微信客戶端。
這裏有一個經驗教訓——運營支撐系統真的很重要。第一個版本的微信後臺是倉促完成的,當時只是完成了基礎業務功能,並沒有配套的業務數據統計等等。
我們在開放註冊後,一時間竟沒有業務監控頁面和數據曲線可以看。
註冊用戶數是臨時從數據庫統計的,在線數是從日誌裏提取出來的,這些數據通過每個小時運行一次的腳本(這個腳本也是當天臨時加的)統計出來,然後自動發郵件到郵件組。
還有其他各種業務數據也通過郵件進行發佈,可以說郵件是微信初期最重要的數據門戶。
2011.1.21 當天最高併發在線數是 491,而今天這個數字是 4 億。
階段二:小步慢跑
在微信發佈後的 4 個多月裏,我們經歷了發佈後火爆註冊的驚喜,也經歷了隨後一直不溫不火的困惑。
這一時期,微信做了很多旨在增加用戶好友量,讓用戶聊得起來的功能。
打通騰訊微博私信、羣聊、工作郵箱、QQ / 郵箱好友推薦等等。
對於後臺而言,比較重要的變化就是這些功能催生了對異步隊列的需求。
例如,微博私信需要跟外部門對接,不同系統間的處理耗時和速度不一樣,可以通過隊列進行緩衝;
羣聊是耗時操作,消息發到羣后,可以通過異步隊列來異步完成消息的擴散寫等等。
單聊和羣聊消息發送過程
這是異步隊列在羣聊中的應用。微信的羣聊是寫擴散的,也就是說發到羣裏的一條消息會給羣裏的每個人都存一份(消息索引)。
微信的羣聊爲什麼不是讀擴散呢?
有兩個原因:
羣的人數不多,羣人數上限是 10(後來逐步加到 20、40、100,目前是 500),擴散的成本不是太大,不像微博,有成千上萬的粉絲,發一條微博後,每粉絲都存一份的話,一個是效率太低,另一個存儲量也會大很多;
消息擴散寫到每個人的消息存儲(消息收件箱)後,接收者到後臺同步數據時,只需要檢查自己收件箱即可,同步邏輯跟單聊消息是一致的,這樣可以統一數據同步流程,實現起來也會很輕量。
異步隊列作爲後臺數據交互的一種重要模式,成爲了同步 RPC 服務調用之外的有力補充,在微信後臺被大量使用。
KVSvr
微信後臺每個存儲服務都有自己獨立的存儲模塊,是相互獨立的。
每個存儲服務都有一個業務訪問模塊和一個底層存儲模塊組成。
業務訪問層隔離業務邏輯層和底層存儲,提供基於 RPC 的數據訪問接口;底層存儲有兩類:
-
SDB
-
MySQL
SDB 適用於以用戶 UIN(uint32_t) 爲 Key 的數據存儲,比方說消息索引和聯繫人。
優點是性能高,在可靠性上,提供基於異步流水同步的 Master-Slave 模式,Master 故障時,Slave 可以提供讀數據服務,無法寫入新數據。
由於微信賬號爲字母 + 數字組合,無法直接作爲 SDB 的 Key,所以微信帳號數據並非使用 SDB,而是用 MySQL 存儲的。
MySQL 也使用基於異步流水複製的 Master-Slave 模式。
第 1 版的帳號存儲服務使用 Master-Slave 各 1 臺。
Master 提供讀寫功能,Slave 不提供服務,僅用於備份。
當 Master 有故障時,人工切讀服務到 Slave,無法提供寫服務。
爲提升訪問效率,我們還在業務訪問模塊中加入了 memcached 提供 Cache 服務,減少對底層存儲訪問。
第 2 版的帳號存儲服務還是 Master-Slave 各 1 臺,區別是 Slave 可以提供讀服務,但有可能讀到髒數據,因此對一致性要求高的業務邏輯,例如註冊和登錄邏輯只允許訪問 Master。
當 Master 有故障時,同樣只能提供讀服務,無法提供寫服務。
第 3 版的帳號存儲服務採用 1 個 Master 和多個 Slave,解決了讀服務的水平擴展能力。
第 4 版的帳號服務底層存儲採用多個 Master-Slave 組,每組由 1 個 Master 和多個 Slave 組成,解決了寫服務能力不足時的水平擴展能力。
最後還有個未解決的問題:單個 Master-Slave 分組中,Master 還是單點,無法提供實時的寫容災,也就意味着無法消除單點故障。
另外 Master-Slave 的流水同步延時對讀服務有很大影響,流水出現較大延時會導致業務故障。
於是我們尋求一個可以提供高性能、具備讀寫水平擴展、沒有單點故障、可同時具備讀寫容災能力、能提供強一致性保證的底層存儲解決方案,最終 KVSvr 應運而生。
KVSvr 使用基於 Quorum 的分佈式數據強一致性算法,提供 Key-Value/Key-Table 模型的存儲服務。
傳統 Quorum 算法的性能不高,KVSvr 創造性地將數據的版本和數據本身做了區分。
將 Quorum 算法應用到數據的版本的協商,再通過基於流水同步的異步數據複製提供了數據強一致性保證和極高的數據寫入性能。
另外 KVSvr 天然具備數據的 Cache 能力,可以提供高效的讀取性能。
KVSvr 一舉解決了我們當時迫切需要的無單點故障的容災能力。
除了第 5 版的帳號服務外,很快所有 SDB 底層存儲模塊和大部分 MySQL 底層存儲模塊都切換到 KVSvr。
隨着業務的發展,KVSvr 也不斷在進化着,還配合業務需要衍生出了各種定製版本。
現在的 KVSvr 仍然作爲核心存儲,發揮着舉足輕重的作用。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/pU5gvH7ovcRVtnU29xHRHw