Jack Jiang

          我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
          posts - 504, comments - 13, trackbacks - 0, articles - 1

          導航

          公告


            ① 即時通訊開發(fā)社區(qū)
            地址: 52im.net
            專業(yè)的資料、社區(qū)

            ② 關注我的公眾號:

            讓技術不再封閉

            ③ 我的Github
            地址: 點此進入
            好代碼,與大家分享
          <2021年10月>
          262728293012
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(291)

          隨筆檔案

          文章檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          60天內閱讀排行

          本文由阿里閑魚技術團隊有攸分享,原題“向消息延遲說bybye:閑魚消息及時到達方案”,有修訂和改動,感謝作者的分享。

          1、引言

          IM消息作為閑魚用戶重要的交易咨詢工具,核心目標有兩點:

          • 1)第一是保證用戶的消息不丟失;
          • 2)第二是保證用戶的消息及時送達接收方。

          IM消息根據消息的接收方設備是否在線,分為離線和在線推送。數據顯示目前閑魚每天有超過一半以上的IM消息是走在線通道的,而在線消息的到達率、及時性是直接影響用戶體驗的。

          本文將根據閑魚IM消息系統在消息及時性方面的優(yōu)化實踐,詳細分析了IM在線通道面臨的各種技術問題,并通過相應的技術手段來優(yōu)化從而保證用戶消息的及時到達。

          PS:如果您對IM消息可靠性還沒有概念,建議先閱讀這篇入門文章《零基礎IM開發(fā)入門(二):什么是IM系統的實時性?》。

          學習交流:

          - 即時通訊/推送技術開發(fā)交流5群:215477170 [推薦]

          - 移動端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動端IM

          - 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK

          本文同步發(fā)布于:http://www.52im.net/thread-3726-1-1.html

          2、系列文章

          本文是系列文章的第5篇,總目錄如下:

          3、當前面臨的問題

          3.1 端內長連接中斷

          在IM場景中,用戶與云端通信頻繁,且為了實現用戶的消息及時到達,往往采用云端下推消息的方式觸達用戶,所以用戶在線時設備與云端會維持一條TCP長連接通道,可以更輕量級的與服務端進行交互,現代IM即時通訊的下行消息都是通過長連下發(fā)的。

          當前閑魚IM消息系統使用的是ACCS長連接,ACCS是淘寶無線提供的全雙工、低延時、高安全的通道服務。

          但由于用戶設備網絡狀態(tài)的不確定性,可能會發(fā)生各種各樣的網絡異常情況導致ACCS長連接通道中斷。而長連接一旦意外中斷,就會導致用戶無法及時收到在線消息。

          針對這個問題,我們需要盡可能及時的感知到長連中斷并嘗試重連。具體的優(yōu)化思路會在本文后面的內容中分享。

          3.2 下推的消息未達

          感知長連中斷并重連只能在大多數時間保證長連接的有效性,但是在長連接無效或不穩(wěn)定期間下推的消息客戶端可能根本收不到。

          簡單說就是僅僅有重連機制無法保證下行消息必達,可能有以下場景導致下行消息失敗:

          • 1)服務端發(fā)送下行消息時長連暢通,消息在傳輸路上通道斷掉,客戶端無法收到;
          • 2)設備的在線狀態(tài)存在延遲,服務端下行消息時認為設備在線,實際上設備已經離線,無法收到;
          • 3)客戶端收到了下行消息,但端上后續(xù)處理失敗(比如落庫失敗,消息沒有成功展示給用戶)。

          我們通過數據埋點統計得出,ACCS長連接的下行成功率在97%左右。

          ACCS長連接的下行成功率的統計方法如下:

          ACCS下行成功率 = 通過ACCS成功下行且客戶端收到的消息量 / 服務端認為通過ACCS成功下行的消息量

          有心急的同學就要問了,丟了3%的消息嗎?

          并沒有!這3%的消息不會丟失,只是不保證及時觸達給用戶。

          我們的消息同步模型是推拉結合模式,在用戶拉取消息時會拉取到設備當前位點與服務端最新位點的所有消息,ACCS下行失敗的消息會通過主動拉模式獲取到,但客戶端主動拉取消息的觸發(fā)時機有限。

          當前客戶端主動拉取消息的觸發(fā)時機主要有以下幾個:

          • 1)用戶冷啟動app,主動同步消息;
          • 2)用戶主動下拉刷新;
          • 3)app后臺切換前臺;
          • 4)收到一條推送消息,客戶端發(fā)現新消息的位點跟本地最新的位點有gap,觸發(fā)同步。

          可見:上述主動同步消息的觸發(fā)很大程度上依賴用戶行為或者有沒有收到新消息,難以保證消息及時到達。

          如果是用戶高頻打開的IM軟件,這樣也不會有太大的問題。但是閑魚app的活躍度較低,有時候甚至依賴IM消息拉活,而且一條延遲的消息觸達可能導致用戶錯過一筆交易,閑魚消息不允許有這樣的延遲發(fā)生。

          基于上述分析,我們先描述一個數據指標來反映現狀。

          通過上面的描述可知:ACCS消息并不全都是推下來的,也可能是主動拉下來的。如果是推,必定可以及時到達;如果是拉,則受限于用戶行為。

          拉的這部分消息,我們定義為ACCS消息補償到達,然后計算ACCS消息補償到達耗時,消息范圍限定為服務端ACCS成功下行但是客戶端通過主動拉取同步到的消息,以往的版本這個數據在60分鐘左右。

          注意:這個數據并不是消息觸達到用戶的耗時,因為如果在線轉離線觸達,拉取到消息的時間取決于用戶行為(用戶何時打開了app),但這個數據也能大致反映在線消息的到達延遲狀況。

          ACCS長連接的消息補償到達耗時的統計方法如下:

          ACCS消息補償到達耗時 = 客戶端通過拉獲取到ACCS消息的時間 - 服務端ACCS下行時間

          接下來本文將從長連接的重連和未達消息重發(fā)兩個方面詳細講述我們是如何優(yōu)化在線通道穩(wěn)定性的,從而優(yōu)化并保證消息的及時到達。

          4、優(yōu)化手段1:增加長連接重連機制

          4.1 長連接為什么會中斷?

          有因必有果,我們先來分析下有哪些原因會導致連接中斷。

          對于IM這種場景下來說,通常可能有以下原因:

          • 1)用戶設備斷網;
          • 2)設備發(fā)生了網絡切換;
          • 3)設備處于弱網環(huán)境,網絡不穩(wěn)定;
          • 4)設備網絡正常,TCP連接由于NAT超時導致連接被運營商中斷。

          對于APP來說,如果是用戶操作導致網絡狀態(tài)變化的情況,會有網絡狀態(tài)變化事件通知,這種情況可以監(jiān)聽事件并主動嘗試重連。但現實中的大多數情況都是“意料之外”(正如上面列舉的這些斷網可能性一樣)。

          那么既然“意料之外”的斷網無法預知,技術上可以如何有效的感知到各種異常狀況呢?

          PS:如果要透徹理解斷網、弱網、TCP鏈接有效性,并不是本文能講的清楚的,可以參照下面的資料深入理解一下,值得好好學習。

          關于TCP鏈接本身的有效性問題,可以讀以下兩篇:

          1. 為何基于TCP協議的移動端IM仍然需要心跳保活機制?
          2. 不為人知的網絡編程(十二):徹底搞懂TCP協議層的KeepAlive保活機制

          關于移動網絡的復雜性問題,可以從以下幾篇入門的科普文章學習一下:

          1. IM開發(fā)者的零基礎通信技術入門(十一):為什么WiFi信號差?一文即懂!
          2. IM開發(fā)者的零基礎通信技術入門(十二):上網卡頓?網絡掉線?一文即懂!
          3. IM開發(fā)者的零基礎通信技術入門(十三):為什么手機信號差?一文即懂!
          4. IM開發(fā)者的零基礎通信技術入門(十四):高鐵上無線上網有多難?一文即懂!

          關于移動弱網帶來的各種問題、優(yōu)化方案等,可以通過以下幾篇系統學習一下:

          1. 現代移動端網絡短連接的優(yōu)化手段總結:請求速度、弱網適應、安全保障
          2. 移動端IM開發(fā)者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”
          3. 移動端IM開發(fā)者必讀(二):史上最全移動弱網絡優(yōu)化方法總結
          4. 百度APP移動端網絡深度優(yōu)化實踐分享(三):移動端弱網優(yōu)化篇

          4.2 心跳檢測機制

          像大多數鏈路保活場景一樣,IM這種場景下最有效的檢測手段就是心跳檢測(如果你對TCP鏈路保活還沒有什么概念,建議先讀《為何基于TCP協議的移動端IM仍然需要心跳保活機制?)。

          原理就是:客戶端通過定時發(fā)送心跳包,服務端收到心跳包后再反饋給客戶端,通過客戶端和服務端這一來一去的配合,就可以實現客戶服和服務端各自都能感知到連接是否中斷。

          從及時性效果來看:心跳間隔越短越好,而頻繁的心跳檢測勢必會帶來用戶流量以及電量的損耗,所以我們的實現目標是如何盡可能少的心跳檢測而又盡量及時地感知到長連中斷的意外情況。

          狀態(tài)機+消息心跳隊列:

          在心跳協議設計上,要注意心跳包的核心目標是檢測長連通道是否暢通,客戶端主動上行心跳包且能收到服務端回包,就認為長連通道健康。所以心跳的上行消息以及回包的數據包應盡可能小。一般來說,通過協議頭標識心跳包及響應即可(這樣就能節(jié)省協議包大小)。

          PS:關于心跳機制的入門文章可以詳讀《一文讀懂即時通訊應用中的網絡心跳包機制:作用、原理、實現思路等》。

          4.3 心跳策略

          心跳策略是實現我們上述目標的核心機制,本文僅簡單列舉幾種心跳策略。

          比如以下這幾種:

          • 1)短心跳檢測 初始狀態(tài)連續(xù) ping 3次 收到 ACK 后,可以認為進入穩(wěn)定狀態(tài);
          • 2)常規(guī)固定時長心跳(根據app狀態(tài)不同,頻率可調Mid+,Mid-, Long);
          • 3)自適應心跳 根據設備網絡狀態(tài)變化自動適應的心跳間隔;
          • 4)冗余心跳,app后臺切前臺,主動心跳一次。

          關于心跳策略的詳細設計甚至可以單獨寫一篇文章,有興趣的同學可以閱讀以下推薦的文章繼續(xù)深入研究。

          5、優(yōu)化手段2:消息ACK應答與重發(fā)機制

          5.1 概述

          為了解決上面的問題,我們同時也引入了消息ACK應答與重發(fā)機制。

          整體思路是:客戶端在收到ACCS消息并處理成功后,給服務端回一個ACK應答包,服務端下發(fā)ACCS消息時將消息加入重試隊列,收到ACK應答包后更新消息到達狀態(tài),并終止重試。

          整體設計流程圖如下:

          該方案的難點即重試處理器的實現設計,接下來我們將重點講述這部分的詳細設計。

          5.2 重試隊列存儲設計

          我們采用阿里云表格存儲TimeLine模型來存儲下行消息的到達狀態(tài)。Timeline 模型是針對消息數據場景所設計的數據模型,它能滿足消息數據場景對消息保序、海量消息存儲、實時同步的特殊需求,在IM、Feed流等消息場景應用廣泛。(關于TimeLine模型,這里有篇詳細的文章可以學習一下《現代IM系統中聊天消息的同步和存儲方案探討

          我們給每個用戶設備定義一個TimeLine,timeline-id定義為userId_deviceId,sequenceId自定義為消息位點。

          存儲結構如下:

          每通過ACCS成功下行一條消息,則插入到接收用戶設備的TimeLine中,收到ACK后根據消息id更新消息到達狀態(tài)。

          同時由于重試動作只發(fā)生在下行消息后較短的一段時間內,所以我們設置一個比較短的全局過期時間即可,避免數據膨脹。

          5.3 延遲重試設計

          如上圖所示:

          • 1)每通過ACCS下發(fā)一條消息,先插入到Timeline中,初始狀態(tài)為未達,然后生產一條延遲N秒的延遲消息;
          • 2)每次消費到延遲消息后,讀取tablestore中該消息的到達狀態(tài),如到達則終止延遲,否則繼續(xù);
          • 3)每次重試先判斷設備是否在線,如果設備不在線,轉發(fā)離線通道并終止重試,如果設備在線,則重推未到達的消息,并再次延遲N秒消費;
          • 4)每條消息的重試生命周期中用的同一條延遲消息,最多重試消費M次,超過次數不再重試并打日志埋點(后續(xù)可以監(jiān)控這種情況并基于這個數據進行優(yōu)化)。

          5.4 延遲重發(fā)策略

          延遲重發(fā)策略是指在重發(fā)流程中,如何選擇合適的延遲時間來使得重發(fā)的效率最高。

          不同用戶在不同時間、地點所處的網絡環(huán)境差別較大,網絡恢復到穩(wěn)定態(tài)所需要的時間也有差異,需要選用合適的延遲策略來保證重發(fā)效率。

          最優(yōu)的延遲策略的目標是在最短的時間內,使用最少的重發(fā)次數將消息投遞成功。以下是幾種可選的方案。

          5.4.1)固定延遲時間:

          要想找到最優(yōu)的延遲策略,必須從數據中通過分析得到答案,天馬行空的想象往往離實際相差甚遠。

          我們先采用固定的延遲時間(10s)最大重試6次來分析一波數據:

          通過這組數據可以看到:有約85%的消息在40s內重發(fā)可以投遞成功,還有12%的消息在達到最大重試次數后依舊沒有收到ACK。在4次重試之后,第5次成功只有2.03%,第6次只有0.92%,繼續(xù)重發(fā)的收益已經變得很低。

          6次以后還有部分消息沒有收到ACK,這部分消息如果用固定延遲時間策略,性價比很低,頻繁重發(fā)浪費系統資源,我們需要繼續(xù)改進策略。

          5.4.2)固定延遲+固定步長遞增:

          考慮到部分用戶的網絡短時間無法恢復,頻繁的短間隔重發(fā)價值不大,我們采用4次固定短間隔延遲N秒后,每次延遲時間都是上一次延遲時間遞增固定步長M秒的策略。直到收到ACK、用戶設備離線或者達到了最大延遲時間MAX(N)。

          這種策略一定程度上可以解決固定延遲時間重發(fā)策略的問題,但如果用戶短時間網絡無法恢復,每次重發(fā)都要重新遞增,也不是一種最優(yōu)解。

          5.4.3)自適應延遲:

          設計流程圖:

          如上圖:我們最終衍生出了自適應延遲策略。

          自適應延遲是指:根據用戶的網絡狀況,采取自動調整的延遲時間,以期望達到最高的重發(fā)效率。

          具體是:新消息先通過4次固定N秒的短延遲來探測設備的網絡狀況,一旦網絡恢復,我們將設備的N值清空(設備N值是指根據上幾次重發(fā)經驗,當前設備網絡能回復ACK所需要的最短時間,默認情況該值為空,代表用戶設備網絡正常)。4次重發(fā)后依舊收不到ACK,我們嘗試讀取設備N值,如果為空,則取初始值,以后每次延遲都遞增固定步長M,并在重發(fā)后更新當前設備的N值,直到消息收到ACK或者達到了最大延遲時間MAX(N)。

          5.5 新老版本兼容性

          需要注意的是老版本的app是不會回ACK的,如果下發(fā)給老版本設備的消息也加入重試隊列,那此類消息將一直重試到最大次數才會終止,無端消耗資源。

          所以我們設計在ACCS長連建立之后,客戶端主動上行一條設備信息,其中包含app的版本號,服務端存儲一定時間,在將消息加入重試隊列之前,先校驗接收者設備app的版本號,符合要求再加入重試隊列。

          6、 最終優(yōu)化后的效果

          消息重連重發(fā)方案上線后,我們上面定義的指標 ACCS補償到達時間 從60分鐘大幅降低至15分鐘,降幅達75%。

          從而印證了我們的技術分析,同時用戶有關消息延遲的輿情反饋大幅下降,可見消息重發(fā)機制對保證用戶消息及時到達成效顯著。

          7、未來展望

          消息在線通道的穩(wěn)定性優(yōu)化至此已告一段落,未來我們將繼續(xù)優(yōu)化閑魚消息的使用體驗,包括基礎功能的完善以及基礎體驗的提升。

          基礎功能方面:我們在近期的版本中已經支持了消息撤回、草稿功能,后續(xù)將逐步支持發(fā)送定位,會話分組、備注,消息搜索等功能。

          基礎體驗方面:我們對消息的UI樣式做了優(yōu)化升級,并優(yōu)化了app消息tab頁的cpu及內存使用,后續(xù)將繼續(xù)從流量、電量、性能方面繼續(xù)優(yōu)化消息的使用體驗。

          附錄:參考資料

          [1] 為何基于TCP協議的移動端IM仍然需要心跳保活機制?

          [2] 不為人知的網絡編程(十二):徹底搞懂TCP協議層的KeepAlive保活機制

          [3] 現代IM系統中聊天消息的同步和存儲方案探討

          [4] 現代移動端網絡短連接的優(yōu)化手段總結:請求速度、弱網適應、安全保障

          [5] 移動端IM開發(fā)者必讀(二):史上最全移動弱網絡優(yōu)化方法總結

          [6] IM開發(fā)者的零基礎通信技術入門(十二):上網卡頓?網絡掉線?一文即懂!

          [7] IM開發(fā)者的零基礎通信技術入門(十三):為什么手機信號差?一文即懂!

          [8] 移動端IM實踐:實現Android版微信的智能心跳機制

          [9] 融云技術分享:融云安卓端IM產品的網絡鏈路保活技術實踐

          [10] Web端即時通訊實踐干貨:如何讓你的WebSocket斷網重連更快速?

          本文已同步發(fā)布于“即時通訊技術圈”公眾號。

          同步發(fā)布鏈接是:http://www.52im.net/thread-3726-1-1.html



          作者:Jack Jiang (點擊作者姓名進入Github)
          出處:http://www.52im.net/space-uid-1.html
          交流:歡迎加入即時通訊開發(fā)交流群 215891622
          討論:http://www.52im.net/
          Jack Jiang同時是【原創(chuàng)Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
          本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


          只有注冊用戶登錄后才能發(fā)表評論。


          網站導航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 碌曲县| 鹤庆县| 海南省| 阿合奇县| 昔阳县| 乌审旗| 晴隆县| 淮阳县| 迁安市| 怀集县| 青龙| 扬州市| 淄博市| 武宣县| 安化县| 红安县| 沈丘县| 扬州市| 饶河县| 富裕县| 霍林郭勒市| 安溪县| 水城县| 邵阳市| 绍兴县| 西贡区| 汉源县| 大田县| 东光县| 罗江县| 武乡县| 平凉市| 安远县| 深水埗区| 安义县| 嵩明县| 青河县| 江山市| 嘉祥县| 三亚市| 同仁县|