Jack Jiang

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

          本文由鞏鵬軍分享,原題“IM兼容性基建”,本文有修訂。

          1、引言

          一個(gè)成熟的IM成品,在運(yùn)營(yíng)過程中隨著時(shí)間的推移,會(huì)發(fā)布不同的版本,但為了用戶體驗(yàn)并不能強(qiáng)制要求用戶必須升級(jí)到最新版本,而服務(wù)端此時(shí)已經(jīng)是最新版本了,所以為了讓這些不同客戶端版本的用戶都能正常使用(尤其IM這種產(chǎn)品,不同版本可能通信協(xié)議都會(huì)有變動(dòng),這就更要命了),則必須要針對(duì)不同客戶端版本的兼容處理。

          本文將基于筆者的IM產(chǎn)品開發(fā)和運(yùn)營(yíng)實(shí)踐,為你分享如何實(shí)現(xiàn)不同APP客戶端版本與服務(wù)端通信的兼容性處理方案。

           

          學(xué)習(xí)交流:

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

          2、關(guān)于作者

          鞏鵬軍:專注移動(dòng)開發(fā)十多年,熱愛即時(shí)通訊技術(shù)。個(gè)人微信公眾號(hào):“鞏鵬軍”。

          作者在即時(shí)通訊網(wǎng)分享的另一篇《知識(shí)科普:IM聊天應(yīng)用是如何將消息發(fā)送給對(duì)方的?(非技術(shù)篇)》,感興趣的讀者也可以看看。

          3、一個(gè)App時(shí)怎么辦?

          提示:“一個(gè)App”指的是同一個(gè)IM服務(wù)端,只服務(wù)于一個(gè)特定的IM產(chǎn)品。

          首先想到的就是直接使用App版本號(hào)判斷新老版本并進(jìn)行兼容處理。

          如下圖所示:

          一般來說,不同的IM客戶端(如iOS、Android、Windows、Mac)都是同步迭代,多端發(fā)版時(shí)間一致,App版本號(hào)也一樣。

          所以用跨多端的App版本號(hào)可以很容易地讓服務(wù)端只用寫一遍判斷和兼容邏輯。

          示例:假設(shè)從V2.1.0開始應(yīng)用紅包消息,那么判斷客戶端是否支持紅包的邏輯就很簡(jiǎn)單。

          偽代碼如下:

          booleanisSupportRedEnvelop(String appVersion) {

           returngte(appVersion, "2.1.0");

          }

          附:版本號(hào)比對(duì)邏輯(未充分考慮異常情況):

          List<Integer> toNums(String version) {

            Matcher matcher = Pattern

           

              .compile("/[0-9]+\\.[0-9]+\\.[0-9]+")

           

              .matcher(version);

           

            String versionString = matcher.find()

           

              ? matcher.group(0).substring(1)

           

              : "1.0.0";

           

            List<Integer> verNums = Arrays

           

              .stream(versionString.split("\\."))

           

              .map(Integer::valueOf)

               .collect(Collectors.toList());

            returnverNums;

          }

           

          booleangte(String version, String target) {

           

            List<Integer> appVerNums = toNums(version);

            Integer appMajor = appVerNums.get(0);

            Integer appMinor = appVerNums.get(1);

            Integer appPatch = appVerNums.get(2);

            List<Integer> targetNums = toNums(target);

            Integer targetMajor = targetNums.get(0);

            Integer targetMinor = targetNums.get(1);

            Integer targetPatch = targetNums.get(2);

            return(appMajor >= targetMajor) ||

                   (appMinor >= targetMinor) ||

                   (appPatch >= targetPatch);

          }

          4、多個(gè)App時(shí)怎么辦?

          4.1概述

          提示:“多個(gè)App”指的是同一個(gè)IM服務(wù)端,可能作為通用服務(wù),作為多個(gè)不同APP產(chǎn)品中的聊天模塊使用的場(chǎng)景。

          只有一個(gè)App時(shí)肯定是比較簡(jiǎn)單的。但現(xiàn)實(shí)情況是一套IM系統(tǒng)通常會(huì)用于多個(gè)業(yè)務(wù)場(chǎng)景,這是很普遍的現(xiàn)象。業(yè)界的知名IM產(chǎn)品,比如釘釘、飛書、企業(yè)微信、美團(tuán)大象等都是這樣。

          底層邏輯大概是:IM系統(tǒng)比較復(fù)雜,功能繁多而且難以實(shí)現(xiàn)、更難以穩(wěn)定,所以一個(gè)IM團(tuán)隊(duì)維護(hù)一套IM系統(tǒng),然后應(yīng)用在多個(gè)業(yè)務(wù)場(chǎng)景就是最具性價(jià)比的選擇了。

          4.2使用App版本

          每個(gè)業(yè)務(wù)場(chǎng)景都會(huì)有自己的客戶端App,每個(gè)App都有自己的版本號(hào),那么根據(jù)App版本號(hào)判斷新老版本的邏輯就不適用了(如下圖所示)。

          一個(gè)App時(shí)可以這樣做兼容性判斷:

          booleanisSupportRedEnvelop(String appVersion) {

           returngte(appVersion, "2.1.0");

          }

          多個(gè)App時(shí)的兼容性判斷:

          booleanisSupportRedEnvelop(String version) {

              return

              (app.equals("App1")&>e(version,"2.1.0"))||

              (app.equals("App2")&>e(version,"2.2.3"))||

              (app.equals("App3")&>e(version,"6.1"));

          }

          4.3使用App版本號(hào)的麻煩

          隨著App的增多,需要的判斷也越多,這會(huì)很麻煩,也很容易出錯(cuò)。

          每個(gè)App推出新版本后,用戶不可能瞬間就升級(jí)到最新版本,根據(jù)經(jīng)驗(yàn),每個(gè)App往往都會(huì)同時(shí)存在十個(gè)以上的不同版本。

          這就會(huì)形成如下圖所示的局面:

          5、多個(gè)App時(shí),可將IM能力提煉為一套公用代碼

          多個(gè)App時(shí)的問題總結(jié)起來就是:一套服務(wù)端代碼如何適應(yīng)集成了不同IM能力的不同App客戶端?

          我們來具體舉例分析一下,假設(shè)一個(gè)IM團(tuán)隊(duì)維護(hù)的IM相關(guān)的客戶端模塊有IM Client SDK、聯(lián)系人、長(zhǎng)連接、朋友圈等四個(gè)模塊(如下圖所示)。

          如上圖所示:

          • 1)App 1:集成了全部四個(gè)模塊;
          • 2)App 2:只集成了三個(gè)模塊;
          • 3)App 3:只集成了三個(gè)模塊。

          因?yàn)槿齻€(gè)App面向的客戶群不同,發(fā)版節(jié)奏不同,所以各自集成的IM的能力也不同。

          比如下面這樣:

          • 1)App 1:面向內(nèi)部員工辦公溝通使用的App 1需要功能豐富,對(duì)于穩(wěn)定性和Bug有一定的包容性,也容易溝通和修復(fù)再發(fā)版;
          • 2)App 2:面向客服場(chǎng)景,用于企業(yè)的客服專員和企業(yè)的C端用戶溝通解決客訴問題,對(duì)于穩(wěn)定性要求高,C端用戶升級(jí)率不好控制,發(fā)版節(jié)奏慢,最快只能和主業(yè)務(wù)App一致;
          • 3)App 3:面向企業(yè)和B端供應(yīng)商,比如美團(tuán)和美團(tuán)上的商戶,京東和京東平臺(tái)上的第三方商家,對(duì)于穩(wěn)定性要求也比較高,B端商家的升級(jí)率好控制一點(diǎn),發(fā)版節(jié)奏也可以快一些。

          從上圖可以看出,因?yàn)镮M核心能力是同一個(gè)團(tuán)隊(duì)維護(hù),所以Core包含的多個(gè)模塊的代碼必然是只有一套源代碼。不同App只是Core集成打包出來的產(chǎn)物,或者說不同App只是Core外面套了不同的殼而已,只要Core一樣,則App的IM能力就一樣(這就是本節(jié)標(biāo)題所述的“多個(gè)App時(shí),可將IM能力提煉為一套公用的代碼”這個(gè)意思)。

          6、給每個(gè)App中使用的公用代碼(Core)一個(gè)版本號(hào)

          如上節(jié)所述,我們將IM能力提煉為一套公用代碼(以下內(nèi)容簡(jiǎn)稱“Core”)。

          那么,我們能不能給Core一個(gè)版本標(biāo)識(shí)呢?

          答案是肯定的:

          站在App的角度,每個(gè)App相當(dāng)于打上了Core版本標(biāo)簽:

          7、如何正確地解讀Core版呢?

          7.1拋開App看Core版本

          如果不看App版本,只看Core版本標(biāo)簽:

          7.2從一套服務(wù)端代碼看Core版本

          同一個(gè)IM團(tuán)隊(duì),其IM Servers必然也是同一套代碼集,不考慮部署的區(qū)別。

          那么上圖邏輯上等價(jià)于下圖:

          7.3使用Core版本的兼容性判斷

          站在Core的視角,多個(gè)App就像單個(gè)App類似,只是使用的版本標(biāo)識(shí)不同。

          具體如下:

          • 1)單個(gè)App時(shí),IM服務(wù)端要區(qū)分不同App版本;
          • 2)多個(gè)App時(shí),IM服務(wù)端要區(qū)分不同Core版本。

          還拿是否支持紅包的判斷舉例。

          一個(gè)App時(shí):

          booleanisSupportRedEnvelop(String appVersion){

           

          returngte(appVersion, "2.1.0");

          }

          多個(gè)App時(shí):

          booleanisSupportRedEnvelop(Integer coreVersion){

           

           returncoreVersion >= 2;

          }

          通過Core版本號(hào),我們可以把兼容邏輯判斷簡(jiǎn)化到和單個(gè)App一樣的簡(jiǎn)單。

          8、關(guān)于Core版本的命名和取值

          關(guān)于Core版本號(hào)的取值,有下列可能的選項(xiàng):

          • 選項(xiàng)一:語義版本號(hào) 1.2.0;
          • 選項(xiàng)二:整數(shù) 自然數(shù) 1 2 3;
          • 選項(xiàng)三:整數(shù) 迭代日期 20220819 或 220819。

          因?yàn)镃ore版本號(hào)不用給最終用戶看的,無需遵循常見的語義版本號(hào)規(guī)范。而且Core版本號(hào)只用于版本對(duì)比,所以整數(shù)會(huì)是一個(gè)比較好的選擇,方便比較,準(zhǔn)確可靠。

          用自然數(shù) 1、 2、 3作為Core版本號(hào)是可以的,每個(gè)迭代發(fā)布新的Core版本時(shí)遞增一下就可以了。

          但是考慮到有多個(gè)終端平臺(tái)iOS、Android、Windows、Mac,如果某個(gè)平臺(tái)的Core發(fā)布后發(fā)現(xiàn)小Bug需要HotFix,那么要遞增版本號(hào),就會(huì)擠占其它端的下一個(gè)自然數(shù)。究其原因,在于自然數(shù)是連續(xù)的,沒辦法在兩個(gè)常規(guī)的版本間插入一個(gè)HotFix版本。

          選項(xiàng)三就可以解決這個(gè)問題:因?yàn)镃ore的迭代發(fā)布日期是稀疏的,若干天后才會(huì)發(fā)布一個(gè)Core版本,那么當(dāng)某個(gè)端需要一個(gè)HotFix版本時(shí),選擇HotFix當(dāng)天的日期作為版本號(hào)即可。

          總體上:多個(gè)端的主要版本號(hào)都是約定的統(tǒng)一的發(fā)布日期,多端一致,同時(shí)允許某個(gè)端臨時(shí)HotFix插入一個(gè)新的版本號(hào),保留彈性。

          參考 Google 對(duì)Android SDK API版本的實(shí)踐,我們可以把Core版本號(hào)命名為core_level,取值為Core的發(fā)布日期的整數(shù)表示。

          9、多個(gè)App情況下的其它版本標(biāo)識(shí)

          1)platform:

          一套Core,不同端在實(shí)際開發(fā)中,可能存在差異,為了針對(duì)具體端進(jìn)行特定的兼容,需要知道當(dāng)前是哪個(gè)端,可以約定platform字段表示端。取值可以是:ios、android、win、mac、linux等。

          2)App版本號(hào):

          在IM相關(guān)邏輯的兼容性判斷中,只需使用跨App的多端一致的core_level了。但是為了和最終用戶、產(chǎn)品經(jīng)理等溝通方便,保留App版本號(hào)app_version用于人和人之間溝通交流。core_level主要用于研發(fā)工程師之間,還有工程師和程序之間的溝通。兩者各取所長(zhǎng)。

          10、版本標(biāo)識(shí)的傳輸方式

          每個(gè)API和每條長(zhǎng)連接數(shù)據(jù)包都攜帶Core版本,這樣服務(wù)端可以無狀態(tài)得處理每一個(gè)請(qǐng)求。如果需要在服務(wù)端主動(dòng)推送時(shí)區(qū)分目標(biāo)端的版本,可以在App登錄時(shí)將其攜帶的Core版本落庫(kù)存儲(chǔ),然后推送時(shí)查詢使用。

          10.1短連接(HTTP)

          HTTP短連接通過新增Header字段方式傳輸:

          curl "https://{domain}/api/v1/xxx"\

            -H "platform: ios"\

            -H "app_version: 8.0.25"\

            -H "core_level: 220819"

          10.2長(zhǎng)連接(Socket)

          長(zhǎng)連接SDK通過類似HTTP Header的方式傳輸:

          {

            "platform":"ios",

            "app_version":"8.0.25",

            "core_level":"220819"

           

          }

          10.3短轉(zhuǎn)長(zhǎng)

          短轉(zhuǎn)長(zhǎng)時(shí)HTTP Header會(huì)轉(zhuǎn)換為長(zhǎng)連接數(shù)據(jù)body里的header通過長(zhǎng)鏈傳遞。

          這樣就同時(shí)存在長(zhǎng)連接header和長(zhǎng)連接body.header兩套字段,最終以長(zhǎng)連接body.header為準(zhǔn)即可。

          10.4其它

          IM系統(tǒng)里的瀏覽器和小程序,如果可以新增HTTP Header則新增Header傳輸,實(shí)在沒有辦法可以通過User-Agent傳輸該信息,服務(wù)端優(yōu)先解析Header,沒有找到時(shí)再解析User-Agent。

          服務(wù)端解析UA的正則表達(dá)式:

          / platform\/(ios|android|mac|win|linux) app_version\/([0-9]\.[0-9]+\.[0-9]+) core_level\/([1-9][0-9]+)( |$)/

          以上正則表達(dá)式在線運(yùn)行效果:點(diǎn)此查看

          11、本文小結(jié)

          至此,我們找到了一個(gè)適用于多個(gè)App、多個(gè)子模塊、多個(gè)功能點(diǎn)、臨時(shí)BugFix的版本標(biāo)識(shí):Core版本號(hào),這樣就可以很好地解決多App的IM能力兼容性問題。

          以下是版本兼容性判斷偽碼:

          booleanisSupportRedEnvelop(Integer coreLevel) {

            returncoreLevel >= 220819;

          }

          12、參考資料

          [1] Browser vs Engine Version

          [2] Node.js ABI version number

          [3] Android SDK API Level

          [4] 零基礎(chǔ)IM開發(fā)入門(一):什么是IM系統(tǒng)?

          [5] 一套海量在線用戶的移動(dòng)端IM架構(gòu)設(shè)計(jì)實(shí)踐分享(含詳細(xì)圖文)

          [6] 一套原創(chuàng)分布式即時(shí)通訊(IM)系統(tǒng)理論架構(gòu)方案

          [7] 從零到卓越:京東客服即時(shí)通訊系統(tǒng)的技術(shù)架構(gòu)演進(jìn)歷程

          [8] 一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(上篇):整體架構(gòu)、服務(wù)拆分等

          [9] 基于實(shí)踐:一套百萬消息量小規(guī)模IM系統(tǒng)技術(shù)要點(diǎn)總結(jié)

          [10] 一套十萬級(jí)TPS的IM綜合消息系統(tǒng)的架構(gòu)實(shí)踐與思考

          [11] 從新手到專家:如何設(shè)計(jì)一套億級(jí)消息量的分布式IM系統(tǒng)

          [12] 閑魚億級(jí)IM消息系統(tǒng)的架構(gòu)演進(jìn)之路

          [13] 深度解密釘釘即時(shí)消息服務(wù)DTIM的技術(shù)設(shè)計(jì)

          [14] 一套高可用、易伸縮、高并發(fā)的IM群聊、單聊架構(gòu)方案設(shè)計(jì)實(shí)踐

          [15] 企業(yè)微信的IM架構(gòu)設(shè)計(jì)揭秘:消息模型、萬人群、已讀回執(zhí)、消息撤回等

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



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


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


          網(wǎng)站導(dǎo)航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 古浪县| 枣强县| 宝丰县| 临高县| 沂南县| 商城县| 策勒县| 健康| 古田县| 高州市| 石河子市| 富阳市| 仙游县| 南汇区| 威海市| 陆丰市| 京山县| 新干县| 古交市| 巴林左旗| 诸暨市| 张北县| 徐闻县| 昔阳县| 彩票| 湛江市| 静海县| 津市市| 石家庄市| 九寨沟县| 九江县| 临湘市| 浪卡子县| 新河县| 溧阳市| 曲阜市| 湘乡市| 延长县| 南部县| 金乡县| 石首市|