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

本文由微信開發團隊工程師「 kellyliang」原創發表於「微信後臺團隊」公衆號,收錄時有修訂和改動。php

一、引言

隨着直播和類直播場景在微信內的增加,這些業務對臨時消息(在線狀態時的實時消息)通道的需求日益增加,直播聊天室組件應運而生。直播聊天室組件是一個基於房間的臨時消息信道,主要提供消息收發、在線狀態統計等功能。

本文將回顧微信直播聊天室單房間海量用戶同時在線的消息組件技術設計和架構演進,但願能爲你的直播聊天互動中的實時聊天消息架構設計帶來啓發。

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

本文已同步發佈於「即時通信技術圈」公衆號,歡迎關注。公衆號上的連接是:點此進入html

二、相關文章

三、1500萬在線的挑戰

視頻號直播上線後,在產品上提出了直播後臺須要有單房間支撐1500w在線的技術能力。接到這個項目的時候,天然而然就讓人聯想到了一個很是有趣的命題:能不能作到把13億人拉個羣?

微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路_2-0.png
本文將深刻淺出地介紹聊天室組件在演進過程的思考,對這個命題作進一步對探索,嘗試提出更接近命題答案的方案。node

四、直播聊天室1.0架構


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

如上圖所示,能夠看到直播聊天室1.0架構還比較原始和直接,沒有太多複雜的技術應用。

這套架構誕生於2017年,主要服務於微信電競直播間,核心是實現高性能、高實時、高可擴展的消息收發架構。程序員

五、消息擴散方案選型:讀擴散

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

微信中標準的羣消息使用的是寫擴散機制,而直播聊天室跟微信標準羣聊有着巨大的差別。

並且,對於同一人而言,同一時間只能關注一個聊天室,決定了直播聊天室中的消息擴散方案應該使用讀擴散的機制。web

六、longpolling(長輪詢)機制

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

爲了讓用戶須要實時同步到新消息,咱們採用的是longpolling模式。

不少人會疑惑爲何不用websocket,緣由有3個:redis

  • 1)websocket主要考慮推模式,而推模式則有可能丟,作到不丟仍是有須要拉模式來兜底;
  • 2)推模式下,須要精準維護每一個時刻的在線列表,難度很大;
  • 3) longpolling本質是一個短連,客戶端實現更簡單。

七、無狀態cache的設計

很明顯,單純的讀擴散,會形成巨大讀盤的壓力。按照國際慣例,這裏理所應當地增長了一個cache,也就是上面架構圖中的recvsvr。

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

普通的cache都是有狀態的、可穿透的,對常常會出現突發流量的聊天室不是特別友好。而經過異步線程任務,剛好能夠解決這兩個點。

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

① 實時通知:發送消息時,在寫入列表後,向recvsvr集羣發送通知。

② 異步拉取:recvsvr機器收到通知後,觸發異步線程拉取。

③ 兜底輪詢:當recvsvr機器上接收到某個聊天室的請求時,觸發該聊天室的輪詢,保證1s內至少訪問一次消息列表,避免通知失效致使沒法更cache,同時作到機器啓動時數據的自動恢復:
微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路_7.png

④ 無鎖讀取:經過讀寫表分離和原子切換,作到消息的無鎖讀取:
微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路_8.png

⑤ sect化部署:羣數量增多時,擴sect能夠把羣分攤到新的sect上。

無狀態消息cache的設計,不只極大地提升了系統的性能,並且幫助聊天室創建了一個高擴展性消息收發架構。算法

八、技術痛點

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

儘管作到了高性能的消息收發,1.0版本卻並不能實現單房間1500w同時在線的目標。

經過對整個架構和邏輯進一步的分析,咱們發現4個阻礙咱們前進的痛點:數據庫

  • 1)大直播間裏,消息信道不保證全部消息都下發,連麥成功信令丟失會使得連麥功能不可用,大禮物打賞動畫信令丟失會帶來客訴;
  • 2)一個房間的在線列表,是由recvsvr把最近有收取該房間的消息的user聚合到同一臺statsvr獲得的,有單點瓶頸,單機失敗會致使部分房間在線數跳變、在線列表和打賞排行榜不可用等;
  • 3)沒有提供歷史在線人數統計功能;
  • 4)裸的longpolling機制在消息一直有更新的狀況下,沒法控制請求量。

九、直播聊天室2.0架構

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

從上面分析的痛點,咱們得出了聊天室2.0須要解決的問題:小程序

  • 1)解決丟重要信令問題,保證熱點訪問下功能的可靠性;
  • 2)解決在線統計的單點瓶頸,保證熱點訪問下在線統計模塊的可擴展性;
  • 3)實現一個高效準確的歷史在線統計,保證大數據量下統計的高性能和準確性;
  • 4)靈活把控流量,進一步提高隔離和容災能力,保證熱點訪問下系統的可用性。

十、優先級消息列表

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

丟信令的本質緣由:recvsvr只保留最近2000條消息,大直播間裏,有些消息客戶端還沒來的及收就被cache淘汰了。

在聊天室1.0版本,咱們已經證明了寫擴散不可行,所以這裏也不可能經過寫擴散解決。

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

另一個比較直觀的方案:是將重要的系統信令寫到另一個列表裏面,recvsvr同時讀取兩個消息表。帶來的消耗是recvsvr對kv層增長將近一倍的訪問量。因而,咱們思考有沒有更優的方案。

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

回到1.0版本的一個方案細節:咱們能夠看到大部分狀況下,當新消息到來的時候,recvsvr它都是能及時感知到的,所以recvsvr一次拉取到的消息條數並不會不少,所以這一步驟上不會丟消息。

因此咱們是能夠把消息表這個操做收歸到recvsvr裏面的:
微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路_14.png

① 打優先級標記 :依然只寫一張消息表,給重要的信令打上優先級標記。(目的:節省RPC消耗)

② cache內分表:recvsvr拉到消息後分開普通消息列表和重要消息列表;(目的:最小化改動)

③ 優先收取:收取時分normal seq和important seq,先收重要消息表,再收取普通消息表。(目的:優先下發)

經過一個簡單的優化,咱們以最小的改造代價,提供到了一條可靠的重要消息信道,作到了連麥和大禮物動畫的零丟失。微信小程序

十一、分佈式在線統計

11.1 寫共享內存,主從互備

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

參考微信設備在線模塊,咱們能夠有這個一個方案:

  • ① 分sect,一個直播間選一個sect;
  • ② 按roomid選一臺機做爲master, 讀寫該機器的共享內存;
  • ③ master把這個roomid的數據同步到sect內其它機器,master掛了的狀況能夠選其它機器進行讀寫。

上述方案的優缺點:

  • 1)優勢:解決了換機跳變問題。
  • 2)缺點:主備同步方案複雜;讀寫master,大直播間下依然有單機熱點問題。

結論:用分佈式存儲做爲數據的中心節點。

11.2 寫tablekv

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

如上圖所示:

  • ① 用tablekv的一個表來存在線列表,每行記錄用戶id和活躍時間;
  • ② 按期更新用戶的心跳時間,維護在線。

上述方案的優缺點:

  • 優勢:解決了換機跳變問題,數據作到了分佈式;
  • 缺點:1500w在線10s心跳一次 => 9000w/min,穿透寫單表有併發和性能問題;離線不會實時從磁盤刪數據,歷史活躍人數遠大於當前在線,形成數據冗餘。

逐點擊破,單key是能夠經過拆key來解決的,數據冗餘能夠經過key-val存儲作全量替換解決,而穿透問題其實能夠參考recvsvr的實現方式。

所以,咱們獲得一個比較好的方案:拆key + 讀寫分離 + 異步聚合落盤。

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

① 分佈統計 :

  • (1) 每臺機負責部分在線統計;
  • (2) 每臺機內按uin哈希再分多shard打散數據;
  • (3) 每一個shard對應kv的一個key;

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

② 組合數據:讓每臺機都拉取全部key的數據,組合出一個完整的在線列表:
微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路_19.png

③ 異步聚合更新:心跳只更新內存,異步任務清理離線用戶,並把列表序列化到一個key的val。

④ 異步拉取:由異步任務來執行②的拉取和組合數據。

⑤ 原子切換:完整的在線列表作雙指針,利用原子操做無鎖切換,作到無鎖查詢。

由此,咱們提升了心跳更新和在線查詢的性能,作到了在線統計模塊的分佈式部署和可平行擴展。

十二、基於hyperloglog的歷史在線統計

12.1 需求

歷史在線統計,是要曾經看過該直播的用戶數uv,在產品上的體驗就是視頻號直播的「xxx人看過」。

在分佈式在線統計的章節,咱們已經談到了,用tablekv來記錄成員列表是不太可行的。

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

另一個想法:是利用bloomfilter作數據壓縮和去重統計,額外去維護一個count作累加。

那麼這裏有兩點:

  • 一是bloomfilter和count之間要考慮一致性問題;
  • 二是bloomfilter準確率跟壓縮率相關,較好的準確率仍是須要比較大的數據量。

因而咱們調研了業界的一些uv統計方案,最終找到了redis的hyperloglog,它以極小的空間複雜度就能作到64位整形級別的基數估算。

12.2 hyperloglog是什麼?

hyperLogLog 是一種機率數據結構,它使用機率算法來統計集合的近似基數,算法的最本源則是伯努利過程。

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

伯努利過程:設一個硬幣反面爲0,正面爲1,拋一枚硬幣直到結果爲1爲止。

若是作n次伯努利實驗,記錄每次伯努利過程須要拋硬幣的次數爲Ki,則能夠估算:n=2^Kmax

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

hyperloglog對Kmax的計算進行了分桶和調和平均值優化,使得在準確率比裸的伯努利估算要高。

優化的主要內容:

  • ① 將要統計的數據hash成一個64位整形;
  • ② 用低14位來尋找桶的位置;
  • ③ 剩下的高位裏尋找第一個1出現的位置,做爲上述伯努利過程的Ki;
  • ④ 對桶的值進行更新 Rj = max(Rj, Ki);
  • ⑤ 估算時,對各個桶的值算調和平均值DV來替代上述的Kmax。

從上述算法的描述來看:hyperloglog無非就是存了m個桶的數值(m=10000+),原本空間複雜度也不高了。再經過一些位壓縮,hyperloglog把整個數據結構優化到了最大空間複雜度爲12K。

12.3 tablekv+hyperloglog左右開弓

因爲hyperloglog產生的畢竟是近似值,基數較少的時候偏差會更明顯,因此咱們能夠用tablekv來補全歷史在線數較小時的體驗。

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

  • ① 歷史在線數較小時,雙寫tablekv + hyperloglog,以tablekv selectcount爲準;
  • ② 歷史在線數較大時,只寫hyperloglog,以hyperloglog估算值爲準;
  • ③ 在線統計模塊按期把在線列表merge到hyperloglog避免丟數據。

最終咱們達到的效果是:歷史在線不超過1w時徹底準確,超過1w時準確率大於95%。

1三、流量隔離vipsect

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

你們都知道:大直播間會帶來爆發式的請求量,咱們不能讓大直播間引發的失敗影響佔大多數的小直播間。

另外:大直播間影響力大,也要去保證它的良好體驗,那須要用比小直播間更多的機器去支撐。

並且:聊天室對kv層的請求數,跟機器數成正比,小直播間在多機器下會形成大量沒必要要的消耗。

對於這種狀況:咱們參考了微信支付應對大商戶和小商戶的方法,流量隔離,在聊天室的裏設立vip sect。

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

如上圖所示:

  • ① 對可預測的大直播提早加白,直接走vip sect;
  • ② 其它直播直走普通sect;
  • ③ 大小直播策略分級,大直播在線列表才拆key。

雖然還有些依賴運營,可是經過這種方式,咱們切走大部分的大直播流量,也下降了整個系統對kv層的壓力。

那麼:爲何不作自動切vip sect ?

這是一個future work,目前有了一些初步方案,還須要去驗證切換過程帶來影響,進一步細化策略,也歡迎你們提出寶貴建議。

1四、自動柔性下的流量把控

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

在longpolling(長輪詢)的機制下(見本文第6節),直播間一直有消息的話,100w的在線每分鐘至少會產生6kw/min的請求,而1500w更是高達9億/min。logicsvr是cpu密集型的服務,按30w/min的性能來算,至少須要3000臺。

因此這個地方必需要有一些柔性措施把控請求量,尋找一個體驗和成本的平衡點。

而這個措施必定不能經過logicsvr拒絕請求來實現,緣由是longpolling機制下,客戶端接收到回包之後是會立刻發起一次新請求的。logicsvr拒絕越快,請求量就會越大,越容易形成滾雪球。

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

圖片回到longpolling機制,咱們能夠發現,正常運行下,recvsvr沒有新消息時,是可讓請求掛在proxy層hold住,等待鏈接超時或者longpolling notify的。

因此,咱們能夠利用這個特性,柔性讓請求或者回包在proxy hold一段時間,來下降請求頻率。

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

如上圖所示:

  • ① 根據不一樣的在線數設定收取間隔;
  • ② 客戶端上下文裏增長字段,記錄上一次成功收取的時間;
  • ③ 成功收取後的一個時間間隔內,請求hold在proxy層;
  • ④ 根據不一樣的在線數丟棄longpolling notify。

根據400w在線的壓測效果:開啓自適應大招時觸發8~10s檔位,請求量比沒有大招的預期值下降58%,有效地控制了大直播間對logicsvr的壓力。

1五、成果展現

1)支撐多個業務穩定運行:
微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路_29.jpg

2) 壓測1500w同時在線:
微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路_30.jpg

1六、參考文獻

[1] https://zhuanlan.zhihu.com/p/77289303
[2] https://www.jianshu.com/p/4748af30d194

1七、小結與展望

咱們經過抽象問題、精準分析、合理設計完成了liveroom2.0的迭代,從性能、可靠性、可擴展性、容災等方面達到支撐單房間1500w同時在線甚至更高在線的標準。

在將來咱們將繼續優化,好比實現大房間自動從普通sect切換到vip sect,好比針對房間內我的的重要消息通道,使聊天室的功能和架構更增強大。

附錄:微信、QQ團隊分享的其它技術資料

微信朋友圈千億訪問量背後的技術挑戰和實踐總結
微信團隊分享:微信移動端的全文檢索多音字問題解決方案
微信團隊分享:iOS版微信的高性能通用key-value組件技術實踐
微信團隊分享:iOS版微信是如何防止特殊字符致使的炸羣、APP崩潰的?
微信團隊原創分享:iOS版微信的內存監控系統技術實踐
iOS後臺喚醒實戰:微信收款到帳語音提醒技術總結
微信團隊分享:視頻圖像的超分辨率技術原理和應用場景
微信團隊分享:微信每日億次實時音視頻聊天背後的技術解密
微信團隊分享:微信Android版小視頻編碼填過的那些坑
微信手機端的本地數據全文檢索優化之路
企業微信客戶端中組織架構數據的同步更新方案優化實戰
微信團隊披露:微信界面卡死超級bug「15。。。。」的前因後果
QQ 18年:解密8億月活的QQ後臺服務接口隔離技術
月活8.89億的超級IM微信是如何進行Android端兼容測試的
一篇文章get微信開源移動端數據庫組件WCDB的一切!
微信客戶端團隊負責人技術訪談:如何着手客戶端性能監控和優化
微信後臺基於時間序的海量數據冷熱分級架構設計實踐
微信團隊原創分享:Android版微信的臃腫之困與模塊化實踐之路
微信後臺團隊:微信後臺異步消息隊列的優化升級實踐分享
微信團隊原創分享:微信客戶端SQLite數據庫損壞修復實踐
微信Mars:微信內部正在使用的網絡層封裝庫,即將開源
如約而至:微信自用的移動端IM網絡層跨平臺組件庫Mars已正式開源
開源libco庫:單機千萬鏈接、支撐微信8億用戶的後臺框架基石 [源碼下載]
微信新一代通訊安全解決方案:基於TLS1.3的MMTLS詳解
微信團隊原創分享:Android版微信後臺保活實戰分享(進程保活篇)
微信團隊原創分享:Android版微信後臺保活實戰分享(網絡保活篇)
Android版微信從300KB到30MB的技術演進(PPT講稿) [附件下載]
微信團隊原創分享:Android版微信從300KB到30MB的技術演進
微信技術總監談架構:微信之道——大道至簡(演講全文)
微信技術總監談架構:微信之道——大道至簡(PPT講稿) [附件下載]
如何解讀《微信技術總監談架構:微信之道——大道至簡》
微信海量用戶背後的後臺系統存儲架構(視頻+PPT) [附件下載]
微信異步化改造實踐:8億月活、單機千萬鏈接背後的後臺解決方案
微信朋友圈海量技術之道PPT [附件下載]
微信對網絡影響的技術試驗及分析(論文全文)
一份微信後臺技術架構的總結性筆記
架構之道:3個程序員成就微信朋友圈日均10億發佈量[有視頻]
快速裂變:見證微信強大後臺架構從0到1的演進歷程(一)
快速裂變:見證微信強大後臺架構從0到1的演進歷程(二)
微信團隊原創分享:Android內存泄漏監控和優化技巧總結
全面總結iOS版微信升級iOS9遇到的各類「坑」
微信團隊原創資源混淆工具:讓你的APK立減1M
微信團隊原創Android資源混淆工具:AndResGuard [有源碼]
Android版微信安裝包「減肥」實戰記錄
iOS版微信安裝包「減肥」實戰記錄
移動端IM實踐:iOS版微信界面卡頓監測方案
微信「紅包照片」背後的技術難題
移動端IM實踐:iOS版微信小視頻功能技術方案實錄
移動端IM實踐:Android版微信如何大幅提高交互性能(一)
移動端IM實踐:Android版微信如何大幅提高交互性能(二)
移動端IM實踐:實現Android版微信的智能心跳機制
移動端IM實踐:WhatsApp、Line、微信的心跳策略分析
移動端IM實踐:谷歌消息推送服務(GCM)研究(來自微信)
移動端IM實踐:iOS版微信的多設備字體適配方案探討
IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)
IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)
微信多媒體團隊訪談:音視頻開發的學習、微信的音視頻技術和挑戰等
騰訊技術分享:微信小程序音視頻技術背後的故事
微信多媒體團隊梁俊斌訪談:聊一聊我所瞭解的音視頻技術
騰訊技術分享:微信小程序音視頻與WebRTC互通的技術思路和實踐
手把手教你讀取Android版微信和手Q的聊天記錄(僅做技術研究學習)
微信技術分享:微信的海量IM聊天消息序列號生成實踐(算法原理篇)
微信技術分享:微信的海量IM聊天消息序列號生成實踐(容災方案篇)
微信團隊分享:Kotlin漸被承認,Android版微信的技術嚐鮮之旅
社交軟件紅包技術解密(二):解密微信搖一搖紅包從0到1的技術演進
社交軟件紅包技術解密(三):微信搖一搖紅包雨背後的技術細節
社交軟件紅包技術解密(四):微信紅包系統是如何應對高併發的
社交軟件紅包技術解密(五):微信紅包系統是如何實現高可用性的
社交軟件紅包技術解密(六):微信紅包系統的存儲層架構演進實踐
社交軟件紅包技術解密(十一):解密微信紅包隨機算法(含代碼實現)
微信團隊分享:極致優化,iOS版微信編譯速度3倍提高的實踐總結
IM「掃一掃」功能很好作?看看微信「掃一掃識物」的完整技術實現
微信團隊分享:微信支付代碼重構帶來的移動端軟件架構上的思考
IM開發寶典:史上最全,微信各類功能參數和邏輯規則資料彙總
微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路
>> 更多同類文章 ……

本文已同步發佈於「即時通信技術圈」公衆號。

▲ 本文在公衆號上的連接是:點此進入。同步發佈連接是:http://www.52im.net/thread-3376-1-1.html

相關文章
相關標籤/搜索