本文由阿里閑魚技術團隊今朝、有攸分享,本次有修訂。
1、引言
閑魚即時消息系統歷經數代迭代,目前已能穩定的支撐億級消息體量。
在此消息系統的建設過程中,我們經歷了從簡單到復雜、從困擾到破局,每一次的技術改變都是為了更好的解決當下業務所面臨的問題。
本文分享的是閑魚即時消息系統架構從零開始的技術變遷之路,以期更多的同行們在此基礎上汲取經驗,得到有價值的啟發。

學習交流:
- 即時通訊/推送技術開發交流5群:215477170 [推薦]
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK
(本文同步發布於:http://www.52im.net/thread-3699-1-1.html )
2、系列文章
本文是系列文章的第3篇,總目錄如下:
- 《阿里IM技術分享(一):企業級IM王者——釘釘在后端架構上的過人之處》
- 《阿里IM技術分享(二):閑魚IM基於Flutter的移動端跨端改造實踐》
- 《阿里IM技術分享(三):閑魚億級IM消息系統的架構演進之路》(* 本文)
- 《阿里IM技術分享(四):閑魚億級IM消息系統的可靠性投遞技術實踐》(* 稍后發布)
3、1.0版:業務初創期、最小化可用
3.1 技術背景
2014年啟動閑置交易獨立APP “閑魚”,一期構建完成APP主鏈路,包含商品:發布→搜索→商品詳情→IM會話→交易。
作為初創app,業務需盡快上線驗證效果,技術建設上需要完成閑魚消息從無到有的系統搭建。
3.2 技術方案
作為即時通訊系統,最小化能力包含:
- 1)消息存儲:會話、摘要、消息;
- 2)消息同步:推、拉;
- 3)消息通道:長連接、廠商推送。
與一般IM會話模型不同的是,閑魚會話以商品為主體,“人+人+商品”為要素構建會話。
因會話模型的差異,淘系已有的消息系統,短期內無法滿足業務需求,而閑魚完全自建消息系統耗時巨大。
為了保障業務高效上線,技術選型上最大化復用已有系統能力,避免重復造輪子。
所以,我們的技術方案是:
- 1)數據模型與底層存儲依賴淘系私信體系進行建設;
- 2)消息數據獲取上,客戶端全量從服務端拉取消息數據;
- 3)通訊協議使用來往SDK及mtop。
總體架構如下圖,以此模式完成快速交付保障了業務最小化可用:

4、2.0版:用戶量增速快、需要重建消息系統
4.1 技術背景
閑魚用戶量正快速突破100萬,即時消息服務的調用量暴漲。在這樣的背景下,用戶反饋消息數據獲取的卡頓、白屏成為常態,大量的消息Push發送下,系統告警頻發。
造成這些問題的原因:1.0版的架構模式下,獲取消息數據全量拉模式,客戶端純UI不做數據存儲。
具體就是:
- 1)當用戶需要查看消息數據時,數據拉取成功與否取決於網絡、數據訪問速度,偶發性的造成卡頓、白屏;
- 2)中心化的數據存儲,讀遠大於寫,高並發下,服務端負載過大。
針對第2)點:比如1W個用戶同時在線聊天,按照當前架構並發拉取全量消息,估算5萬QPS。不妨假設,同時在線聊天用戶數10萬時,對服務端壓力可想而知。
4.2 技術方案
基於上述問題,我們決定重建消息系統架構,以應對未來更大的用戶增量。
回歸到IM系統的核心功能:

4.2.1)消息存儲模型:
- 1)會話模型:由owner、itemid、user、sessionType 來標識唯一會話,增加擴展屬性支持個性化;
- 2)摘要模型:作為用戶會話視圖,同一會話的不同用戶可個性化呈現,由userid、sid標識唯一摘要;
- 3)消息模型:由sender、消息內容、消息版本、sid組成。sid+消息版本唯一確定一條消息;
- 4)指令模型:是一種雙端約定,由服務端下發,客戶端執行的指令集。如免打擾指令、刪除指令等。
4.2.2)消息通道:
1)在線通道:使用淘寶無線ACCS長連接提供的全雙工、低延時、高安全的通道服務;
2)離線通道:使用淘寶消息推送平台AGOO. 其屏蔽了各主流廠商對接的復雜度,直接對業務系統提供服務。
4.2.3)消息同步模型:
1)客戶端建立數據庫,存儲消息數據:當消息數據存儲在本地設備上,消息同步從全量拉取優化為全量+增量同步結合的模式。
增量和全量同步具體指的是:
- a. 增量同步:客戶端存儲消息位點信息,通過與服務端最新位點比較,僅同步增量消息;
- b. 全量同步:當用戶卸載重裝或位點gap過大時,客戶端全量拉取歷史消息數據,進行端上數據重建。
2)服務端建設個人消息域環(收件箱模型):以和客戶端進行增量數據同步。同時,1.0版本架構中存在的讀多寫少的問題,通過個人域環的寫擴散來平衡讀寫壓力。
下圖為一條消息從發送到接收的過程以及服務端和客戶端的執行流程:

如上圖所示:假設Ua給Ub發送一條消息,消息寫擴散至Ua和Ub的各自的域環中:
- 1)當客戶端online時,接收到推送的消息位點=當前端上域版本+1,本地消息數據庫merge即可;
- 2)當客戶端offline時,僅進行離線推送通知,當用戶重新上線時,進行數據同步,由服務端判斷觸發增量同步還是全量同步。
針對第2)點,具體邏輯是:
- 1)如果域環版本差值小於閥值,增量同步后,進行本地消息數據庫merge;
- 2)當域環版本差值大於閥值,進行全量消息拉取,做端上數據重建。
整個同步邏輯基於閑魚的即時消息域環,域環可以看作是有着固定容量的用戶消息收件箱,給一個用戶發送的所有消息都會同步到他的域環中。
具體就是:
- 1)域環存儲:域環需要支持高並發數據讀寫,使用阿里分布式KV存儲系統tair來實現;
- 2)域環容量:為減少全量消息同步,以用戶下次進入閑魚需要同步的平均消息量來規划個人域環容量。同時利用FIFO循環覆蓋歷史數據;
- 3)域環版本:用戶當前消息位點,在消息進入個人域環時通過tair的counter實現域環版本嚴格連續遞增,用於全量、增量同步判斷。
上述建設完成后,閑魚具備了自己獨立的即時消息系統,當下遇到的問題得到了緩解,用戶體驗度有大幅提升。
5、3.0版:隨着業務快速發展,系統穩定性需得到保障
5.1 技術背景
隨着閑魚業務生態的豐富,IM會話與消息內容類型不斷擴展,同時在用戶量的快速增長下,用戶反饋消息收不到、消息延遲等輿情問題日漸突出。

5.2 問題分析
問題1:閑魚app進程無有效保活機制,app退到后台后進程很快就會被系統掛起,導致長連接中斷。此時消息推送走廠商通道,而廠商通道的實時性較差,且對消息推送的優先級設定有差異,從而造成用戶感知消息延遲。
問題2:accs在線消息推送時,平均延時較短,但存在假連情況。而且目前的消息推送鏈路無ack機制,造成服務端以為消息發出去了但實際上客戶端並沒有收到,用戶下次打開app后才能看到消息,用戶感知消息延遲。
PS:造成假連接的原因主要是用戶退到后台,accs長連中斷,但是設備狀態更新有延時。
問題3:目前消息同步的推模式(accs push)、拉模式(mtop),客戶端未做隔離,異步進行處理,導致在某些極端情況下消息數據庫處理異常,引發消息丟失。
如:某用戶上線后連續收到多條消息,其中一條觸發域黑洞,在進行消息同步端上數據重建時,小概率處理出錯。
問題4:大部分線上消息問題發現靠輿情反饋,如消息錯亂,出問題后系統無感知、無補救措施且排查困難,僅能跟隨版本做修復。
問題5:業務不斷豐富,孵化出基於消息系統的服務號及小程序內容營銷、消息群組等,各類消息發送鏈路共用域環與數據存儲,造成穩定性問題。
如:個人域環的消息包括IM聊天和營銷消息,IM聊天由用戶觸發,需要保證強到達;而營銷消息一般是由系統通過班車等方式批量發送,消息量級大,tps高,影響IM服務穩定性。
5.3 解案決方案
基於上述分析,我們逐個問題進行專項解決。
1)消息重發與推拉隔離:

如上圖所示:
- a. ACK:保障消息及時到達。服務端下行accs消息時,將消息加入重試隊列並延遲重試,客戶端在收到accs消息並處理成功后,給服務端回一個ack,服務端收到ack后更新消息到達狀態,並終止重試,以此避免設備假連或網絡不穩定的情況;
- b. 重發:根據延遲重發策略決定何時重發消息,保障消息確定性到達。自適應延遲重發策略是指新消息先通過4次固定N秒的短延遲來探測設備的網絡狀況,然后根據網絡狀況來遞增固定步長M的延遲策略,這種策略可以保障在最短的時間內,使用最少的重發次數將消息投遞成功;
- c. 消息隊列:端上引入消息隊列,按順序處理消息,保證消息處理的准確性。同時進行推拉隔離,保障隊列有序消費,解決了復雜狀況下並發處理消息數據合並出錯的問題。
2)數據存儲拆分:
閑魚每天發送的即時消息中有一半以上是營銷消息,營銷消息的發送具有明顯的波峰波谷流量,高峰期會導致消息數據庫抖動,影響IM消息。我來對消息、摘要、域環存儲做業務隔離,以適應不同業務場景對穩定性不同的要求。
具體做法是:
- 1)IM消息需要極高的穩定性保證,其消息及摘要繼續使用mysql存儲;
- 2)營銷消息存儲周期短,穩定性要求低於IM,采用Lindorm存儲;
- 3)域環做實例級別隔離,保證IM域環的容量不會被其他消息占用,從而影響到消息同步。
PS:Lindorm是一種多模型的雲原生數據庫服務,具有成本低、自定義TTL、容量橫向擴展等優勢。

3)線上問題發現與恢復:
保障穩定性的關鍵要素是做好各種核心指標的監控,而監控首先要有數據來源,對服務端+客戶端的關鍵鏈路節點埋點,基於集團UT、SLS,通過blink進行實時清洗、計算,最終形成統一規范的日志數據落至SLS,以供實時監控及鏈路排查。
消息系統的核心目標是保障用戶消息發的出、收得到且及時收到,所以我們通過計算發送成功率、到達率、消息延遲來監控系統的穩定性。
此外,為了解決用戶輿情排查困難的問題:
- 1)我們設計了一套指令集,通過約定指令協議,服務端向指定用戶下發指令,客戶端執行對應指令進行異常數據上報,提高排查效率;
- 2)擴展了強制全量同步、數據校正等指令,定向修復用戶消息數據問題,相較以往出現嚴重bug只能讓用戶卸載重裝解決,這種方式顯然對用戶是更友好的。

經過一系列專項治理,技術類輿情下降50%,從0到1建設了消息穩定性體系,用戶體驗進一步提升。
6、展望未來
閑魚作為電商交易APP, 其中IM是交易的前置鏈路,IM的產品體驗極大影響用戶交易效率。
前段時間進行用戶調研,從閑魚IM的NPS低於預期(NPS是用戶忠誠度衡量指標 = 推薦者%-貶損者%)。
從用戶反饋來看:
- 1)部分用戶對產品功能有較強烈的訴求,諸如消息搜索、分組等;
- 2)大部分用戶對發送消息過程中的違規問題難以理解;
- 3)仍有較多輿情反饋消息收不到或延遲。
映射到目前閑魚的即時消息系統上,我們的系統架構依然有很多需要持續改進的地方。
典型的如:同步協議冗余,在需求迭代過程中容易引發問題、有效保活機制的缺失對消息即時送達的影響、小眾機型離線消息收不到、多年的數據積累在線庫臃腫等問題,影響着閑魚業務迭代速度與NPS。
作為技術團隊,下一步將提升NPS作為核心技術目標,閑魚的即時消息系統4.0版架構正在路上 ......
附錄:更多相關文章
[1] 更多阿里巴巴的技術資源:
《阿里釘釘技術分享:企業級IM王者——釘釘在后端架構上的過人之處》
《阿里技術分享:阿里自研金融級數據庫OceanBase的艱辛成長之路》
《來自阿里OpenIM:打造安全可靠即時通訊服務的技術實踐分享》
《釘釘——基於IM技術的新一代企業OA平台的技術挑戰(視頻+PPT) [附件下載]》
《阿里技術結晶:《阿里巴巴Java開發手冊(規約)-華山版》[附件下載]》
《重磅發布:《阿里巴巴Android開發手冊(規約)》[附件下載]》
《阿里技術分享:電商IM消息平台,在群聊、直播場景下的技術實踐》
《阿里技術分享:閑魚IM基於Flutter的移動端跨端改造實踐》
《阿里IM技術分享(三):閑魚億級IM消息系統的架構演進之路》
[2] 有關IM架構設計的文章:
《一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)》
《子彈短信光鮮的背后:網易雲信首席架構師分享億級IM平台的技術實踐》
《微信技術分享:微信的海量IM聊天消息序列號生成實踐(算法原理篇)》
《一套高可用、易伸縮、高並發的IM群聊、單聊架構方案設計實踐》
《社交軟件紅包技術解密(一):全面解密QQ紅包技術方案——架構、技術實現等》
《從游擊隊到正規軍(一):馬蜂窩旅游網的IM系統架構演進之路》
《從游擊隊到正規軍(二):馬蜂窩旅游網的IM客戶端架構演進和實踐總結》
《從游擊隊到正規軍(三):基於Go的馬蜂窩旅游網分布式IM系統技術實踐》
《瓜子IM智能客服系統的數據架構設計(整理自現場演講,有配套PPT)》
《IM開發基礎知識補課(九):想開發IM集群?先搞懂什么是RPC!》
《阿里技術分享:電商IM消息平台,在群聊、直播場景下的技術實踐》
《一套億級用戶的IM架構技術干貨(上篇):整體架構、服務拆分等》
《一套億級用戶的IM架構技術干貨(下篇):可靠性、有序性、弱網優化等》
《企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等》
《IM開發技術學習:揭秘微信朋友圈這種信息推流背后的系統設計》
《阿里IM技術分享(三):閑魚億級IM消息系統的架構演進之路》
>> 更多同類文章 ……
本文已同步發布於“即時通訊技術圈”公眾號。