Jack Jiang

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

          導航

          公告


            ① 即時通訊開發社區
            地址: 52im.net
            專業的資料、社區

            ② 關注我的公眾號:

            讓技術不再封閉

            ③ 我的Github
            地址: 點此進入
            好代碼,與大家分享
          <2020年11月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          常用鏈接

          留言簿(289)

          隨筆檔案

          文章檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          60天內閱讀排行

          本文引用了沈劍《如何保證IM實時消息的“時序性”與“一致性”?》一文的圖片和內容(由于太懶,圖沒重新畫),原文鏈接在文末。

          1、引言

          本文接上篇《零基礎IM開發入門(三):什么是IM系統的可靠性?》,講解IM系統中消息時序的一致性問題。

          所謂的一致性,在IM中通常指的是消息時序的一致性,那就是:

          • 1)聊天消息的上下文連續性;
          • 2)聊天消息的絕對時間序。

          再具體一點,IM消息的一致性體現在:

          • 1)單聊時:要保證發送方發出聊天消息的順序與接收方看到的順序一致;
          • 2)群聊時:要保證所有群員看到的聊天消息,與發送者發出消息時的絕對時間序是一致的。

          IM系統中消息時序的一致性問題是個看似簡單,實則非常有難度的技術熱點話題之一,本文盡量以通俗簡顯的文字為你講解IM消息時序一致性問題的產品意義、發生原因、解決思路等

          • 學習交流:

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

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

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

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

          2、系列文章

          零基礎IM開發入門(一):什么是IM系統?

          零基礎IM開發入門(二):什么是IM系統的實時性?

          零基礎IM開發入門(三):什么是IM系統的可靠性?

          零基礎IM開發入門(四):什么是IM系統的消息時序一致性?》(* 本文

          《零基礎IM開發入門(五):什么是IM系統的安全性? (稍后發布)》

          《零基礎IM開發入門(六):什么是IM系統的的心跳機制? (稍后發布)》

          《零基礎IM開發入門(七):如何理解并實現IM系統消息未讀數? (稍后發布)》

          《零基礎IM開發入門(八):如何理解并實現IM系統的多端消息漫游? (稍后發布)》

          3、消息時序的一致性,對于IM的意義

          現如今,由于移動互聯網的普及,現代人的實際社交關系,幾乎完全是靠IM這種即時通訊社交工具所組織起來的,IM這種工具的重要性不言而喻。

          IM在現代人的生活中,越來越重要,但也越來平常。現在想聯系一個人,第一時間想到的不是打個電話,而是發個“微信”或“QQ”。是的,IM這玩意承載的意義越來越多。

          消息時序的一致性問題,對于IM的意義,毫無疑問帶來的不只是簡簡單單的所謂用戶體驗問題。我們來看看例子。

          假設:你跟女神的表白正進入到關鍵階段,聊著聊著就因為這爛IM,導致聊天消息前言不搭后語,此刻1000公里外你的女神真一臉蒙逼的盯著手機看你的“醉話”,后果是多么嚴重——這半年來的“舔狗”生活、忍辱負重,算是白白被程序員這群“格子衫”、“地中海”們給禍害了。

          再往嚴重了說,就因為這爛IM,讓你失去了這難得的借助女神優良基因,改造家族后代顏值的絕佳機會,無不讓人痛心疾首。。。

          上面這個例子,說的還只是單聊,如果是群聊,則問題可能還會被無限放大:試想一個技術交流群,正在激烈的爭吵著“php是世界最好語言”這種話題的時候,忽然就想砸手機了,不是因為吵的太兇,而因為消息順序全亂完全沒法看,已經嚴重影響鍵盤俠們積極發表個人意見了。

          4、憑什么說保證消息時序的一致性很困難?

          4.1 基本認知

          在普通IM用戶的眼里,消息無非是從一臺手機傳遞到另一臺手機而已,保證時序有何困難?

          是的,普通用戶這么認為,從技術上講,他只是單純的將IM消息的收發過程理解為單線程的工作模式而已。

          實際上,在IM這種高性能場景下,服務端為了追求高吞吐、高并發,用到了多線程、異步IO等等技術。

          在這種情況下,“高并發”與“順序”對于IM服務端來說,本來就是矛盾的,這就有點魚與熊掌的味道了(兩者很難兼得)。

          所以,要實現IM場景下的消息時序一致性,需要做出權衡,而且要考慮的技術維度相當多。這就導致具體技術實施起來沒有固定的套路,而由于開發者技術能力的參差不齊,也就使得很多IM系統在實際的效果上會有較大問題,對于用戶而言也將直接在產品體驗上反應出來。

          下面將具體說明技術難點所在。

          4.2 沒有全局時鐘

          如上圖所示,一個真正堪用的生產系統,顯示不可能所有服務都跑在一臺服務器上,分布式環境是肯定的。

          那么:在分布式環境下,客戶端+服務端后臺的各種后臺服務,都各自分布在不同的機器上,機器之間都是使用的本地時鐘,沒有一個所謂的“全局時鐘”(也沒辦法做到真正的全局時鐘),那么所謂的消息時序也就沒有真正意義上的時序基準點。所以消息時序問題顯然不是“本地時間”可以完全決定的。

          4.3 多發送方問題

          服務端分布式的情況下,不能用“本地時間”來保證時序性,那么能否用接收方本地時間表示時序呢?

          遺憾的是,由于多個客戶端的存在(比如群聊時),即使是一臺服務器的本地時間,也無法表示“絕對時序”。

          如上圖所示:絕對時序上,APP1先發出msg1,APP2后發出msg2,都發往服務器web1,網絡傳輸是不能保證msg1一定先于msg2到達的,所以即使以一臺服務器web1的時間為準,也不能精準描述msg1與msg2的絕對時序。

          4.4 多接收方問題

          多發送方不能保證時序,假設只有一個發送方,能否用發送方的本地時間表示時序呢?遺憾的是,由于多個接收方的存在,無法用發送方的本地時間,表示“絕對時序”。

          如上圖,絕對時序上,web1先發出msg1,后發出msg2,由于網絡傳輸及多接收方的存在,無法保證msg1先被接收到先被處理,故也無法保證msg1與msg2的處理時序。

          4.5 網絡傳輸與多線程問題

          既然多發送方與多接收方都難以保證絕對時序,那么假設只有單一的發送方與單一的接收方,能否保證消息的絕對時序一致性呢?

          結論是悲觀的,由于網絡傳輸與多線程的存在,這仍然不行。

          如上圖所示,web1先發出msg1、后發出msg2,即使msg1先到達(網絡傳輸其實還不能保證msg1先到達),由于多線程的存在,也不能保證msg1先被處理完。

          5、如何保證絕對的消息時序一致性?

          通過上一章內容的總結,我們已經對IM中消息時序一致性問題所產生的緣由,有了較為深刻的認識。

          從純技術的角度來說,假設:

          • 1)只有一個發送方;
          • 2)一個接收方;
          • 3)上下游連接只有一條socket連接;
          • 4)通過阻塞的方式通訊。

          這樣的情況下,難道不能保證先發出的消息被先處理,進而被先展示給消息的接收者嗎?

          是的,可以!

          但實際生產情況下不太可能出現這種IM系統,必竟單發送方、單接收方、單socket連接、阻塞方式,這樣的IM一旦做出來,產品經理會立馬死給你看。。。

          6、實用的優化思路

          6.1 一對一單聊的消息一致性保證思路

          假設兩人一對一聊天,發送方A依次發出了msg1、msg2、msg3三條消息給接收方B,這三條消息該怎么保證顯示時序的一致性(發送與顯示的順序一致)?

          我們知道,發送方A依次發出的msg1、msg2、msg3三條消息,到底服務端后,再由服務端中轉發出時,這個順序由于多線程的網絡的問題,是有可能亂序的。

          那么結果就可能是這樣: 

          如上圖所示,會出現與發出時的消息時序不一致問題(收到的消息順序是:msg3、msg1、msg2)。

          不過,實際上一對一聊天的兩個人,并不需要全局消息時序的一致(因為聊天只在兩人的同一會話在發生),只需要對于同一個發送方A,發給B的消息時序一致就行了。

          常見優化方案,在A往B發出的消息中,加上發送方A本地的一個絕對時序(比如本機時間戳),來表示接收方B的展現時序。

          那么當接收方B收到消息后,即使極端情況下消息可能存在亂序到達,但因為這個亂序的時間差對于普通用戶來說體感是很短的,在UI展現層按照消息中自帶的絕對時序排個序后再顯示,用戶其實是沒有太多感知的。

          6.2 多對多群聊的消息一致性保證思路

          假設N個群友在一個IM群里聊天,應該怎樣保證所有群員收到消息的顯示時序一致性呢?

          首先:不能像一對聊天那樣利用發送方的絕對時序來保證消息順序,因為群聊發送方不單點,時間也不一致。

          或許:我們可以利用服務器的單點做序列化。

          如上圖所示,此時IM群聊的發送流程為:

          • 1)sender1發出msg1,sender2發出msg2;
          • 2)msg1和msg2經過接入集群,服務集群;
          • 3)service層到底層拿一個唯一seq,來確定接收方展示時序;
          • 4)service拿到msg2的seq是20,msg1的seq是30;
          • 5)通過投遞服務講消息給多個群友,群友即使接收到msg1和msg2的時間不同,但可以統一按照seq來展現。

          這個方法:

          • 1)優點是:能實現所有群友的消息展示時序相同;
          • 2)缺點是:這個生成全局遞增序列號的服務很容易成為系統瓶頸。

          還有沒有進一步的優化方法呢?

          從技術角度看:群消息其實也不用保證全局消息序列有序,而只要保證一個群內的消息有序即可,這樣的話,“消息id序列化”就成了一個很好的思路。

          上圖這個方案中,service層不再需要去一個統一的后端拿全局seq(序列號),而是在service連接池層面做細小的改造,保證一個群的消息落在同一個service上,這個service就可以用本地seq來序列化同一個群的所有消息,保證所有群友看到消息的時序是相同的。

          關于IM的系統架構下使用怎么樣實現消息序列化,或者說全局消息ID的生成方案,這又是另一個很熱門的技術話題。

          有興趣,可以深入閱讀下面這個系列:

          IM消息ID技術專題(一):微信的海量IM聊天消息序列號生成實踐(算法原理篇)

          IM消息ID技術專題(二):微信的海量IM聊天消息序列號生成實踐(容災方案篇)

          IM消息ID技術專題(三):解密融云IM產品的聊天消息ID生成策略

          IM消息ID技術專題(四):深度解密美團的分布式ID生成算法

          IM消息ID技術專題(五):開源分布式ID生成器UidGenerator的技術實現

          IM消息ID技術專題(六):深度解密滴滴的高性能ID生成器(Tinyid)

          這個系列中,尤其微信的趨勢遞增ID生成思路(注意:趨勢遞增不是嚴格遞增,趨勢遞增意味著中問有ID被跳過也沒事),對于分布式IM的消息ID來說是非常切實可行的。

          是的,對于IM系統來說,絕對意義上的時序很難保證,但通過服務端生成的單調遞增消息ID的方式,利用遞增ID來保證時序性,也是一個很可性的方案。

          7、小結一下

          IM系統架構下,消息的絕對時序是很困難的,原因多種多樣,比如:沒有全局時鐘、多發送方、多接收方、多線程、網絡傳輸不確定性等。

          一對一單聊時,其實只需要保證發出的時序與接收的時序一致,就基本能讓用戶感覺不到亂序了。

          多對多的群聊情況下,保證同一群內的所有接收方消息時序一致,也就能讓用戶感覺不到亂序了,方法有兩種,一種單點絕對時序,另一種實現消息id的序列化(也就是實現一種全局遞增消息ID)。

          8、參考資料

          [1] 如何保證IM實時消息的“時序性”與“一致性”?,作者:沈劍

          [2] 一個低成本確保IM消息時序的方法探討,作者:封宇

          附錄:更多IM開發熱門技術點

          移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”

          移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結

          現代移動端網絡短連接的優化手段總結:請求速度、弱網適應、安全保障

          移動端IM中大規模群消息的推送如何保證效率、實時性?

          移動端IM開發需要面對的技術問題

          開發IM是自己設計協議用字節流好還是字符流好?

          請問有人知道語音留言聊天的主流實現方式嗎?

          如何保證IM實時消息的“時序性”與“一致性”?

          一個低成本確保IM消息時序的方法探討

          IM單聊和群聊中的在線狀態同步應該用“推”還是“拉”?

          IM群聊消息如此復雜,如何保證不丟不重?

          談談移動端 IM 開發中登錄請求的優化

          移動端IM登錄時拉取數據如何作到省流量?

          淺談移動端IM的多點登錄和消息漫游原理

          完全自已開發的IM該如何設計“失敗重試”機制?

          微信對網絡影響的技術試驗及分析(論文全文)

          IM開發基礎知識補課(五):通俗易懂,正確理解并用好MQ消息隊列

          微信技術分享:微信的海量IM聊天消息序列號生成實踐(算法原理篇)

          IM開發基礎知識補課(六):數據庫用NoSQL還是SQL?讀這篇就夠了!

          IM里“附近的人”功能實現原理是什么?如何高效率地實現它?

          IM的掃碼登錄功能如何實現?一文搞懂主流應用的掃碼登錄技術原理

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

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

          ▲ 本文在公眾號上的鏈接是:點此進入,原文鏈接是:http://www.52im.net/thread-3189-1-1.html



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


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


          網站導航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 台东县| 元氏县| 望江县| 炎陵县| 普兰县| 石首市| 微博| 缙云县| 东乡县| 南乐县| 海口市| 泸定县| 色达县| 中牟县| 新建县| 密云县| 临潭县| 舞钢市| 垦利县| 英吉沙县| 斗六市| 东安县| 额济纳旗| 永年县| 玉山县| 石河子市| 梁山县| 基隆市| 尚志市| 贵定县| 伊通| 林口县| 岑溪市| 多伦县| 樟树市| 黄石市| 贡觉县| 澄江县| 石河子市| 顺平县| 图木舒克市|