得物自研客服IM中收發(fā)聊天消息背后的技術(shù)邏輯和思考實(shí)現(xiàn)

本文由得物技術(shù)WWQ分享,原題“客服發(fā)送一條消息背后的技術(shù)和思”,本文有修訂和改動(dòng)。
1、引言
在企業(yè)IM客服場(chǎng)景中,客服發(fā)送一條消息的背后,需要考慮網(wǎng)絡(luò)通信、前端展示、后端存儲(chǔ)以及安全性等多個(gè)方面的技術(shù)支持。單從前端層面來(lái)說(shuō),就需要考慮到消息的顯示、狀態(tài)更新、穩(wěn)定傳輸以及極限操作消息不卡頓等場(chǎng)景。隨著IM系統(tǒng)的不斷更新迭代,已經(jīng)實(shí)現(xiàn)了從外采到自研再到一站式全場(chǎng)景工作臺(tái)的搭建,我們能夠很明顯地感知到客服對(duì)于IM的體驗(yàn)要求越來(lái)越高了,因此客服發(fā)送一條消息背后所涉及的技術(shù)和思考也越來(lái)越重要。
本文將探秘得物自研客服IM中收發(fā)聊天消息背后的技術(shù)邏輯和思考實(shí)現(xiàn),幫助大家了解如何在IM聊天場(chǎng)景中提供高效、安全、可靠和良好的用戶體驗(yàn)。

?技術(shù)交流:
- 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM》
- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點(diǎn)此)
(本文已同步發(fā)布于:http://www.52im.net/thread-4483-1-1.html)
2、相關(guān)文章
《得物基于Electron開發(fā)客服IM桌面端的技術(shù)實(shí)踐》
《得物從0到1自研客服IM系統(tǒng)的技術(shù)實(shí)踐之路》
3、IM聊天消息的重要性
IM聊天消息是客服和用戶之間最快速、最直觀、最高效的雙向溝通方式之一。
IM聊天的重要性體現(xiàn)在以下幾個(gè)方面:
1)即時(shí)響應(yīng):及時(shí)地解答用戶咨詢的問(wèn)題,更快捷的服務(wù)用戶,提高用戶滿意度;
2)個(gè)性化互動(dòng):可以根據(jù)用戶的需求快速做出個(gè)性化回應(yīng),從而更好地滿足用戶需求;
3)數(shù)據(jù)處理和分析:通過(guò)對(duì)IM聊天消息的處理分析,可以洞察用戶需求、用戶行為,幫助改進(jìn)服務(wù)質(zhì)量。
綜上:IM聊天消息的重要性在于提高用戶滿意度、提高客服作業(yè)效率,這也意味著IM消息的可靠、高效、安全尤為重要,接下來(lái)本文就從前端視角對(duì)客服發(fā)送一條消息背后的技術(shù)和思考進(jìn)行詳細(xì)的講述。
4、客服IM消息發(fā)展歷程
以下是得物客服IM消息發(fā)展的歷程,列舉的都是核心技術(shù)專項(xiàng)的里程碑節(jié)點(diǎn)。

在這個(gè)過(guò)程中,我們積累了一定的經(jīng)驗(yàn)和技能,同時(shí)也遇到了各種各樣的問(wèn)題和挑戰(zhàn)。比如:消息丟失、消息發(fā)送失敗、消息重復(fù)、消息亂序等等方面的問(wèn)題。
針對(duì)這些問(wèn)題我們也都通過(guò)技術(shù)專項(xiàng)的方式去逐個(gè)解決并達(dá)到了預(yù)期效果,我們相信,隨著技術(shù)的不斷發(fā)展和創(chuàng)新,我們可以更好地提供更加高效便捷的服務(wù)。
5、技術(shù)邏輯和思考
站在用戶/客服角度,發(fā)送消息不就是輸入消息后點(diǎn)擊回車鍵或點(diǎn)擊發(fā)送按鈕就完成了嗎。
看似非常簡(jiǎn)單,但是從開始輸入消息到對(duì)方收到消息這個(gè)過(guò)程實(shí)際上有非常強(qiáng)大的技術(shù)在高效、穩(wěn)定支撐。
我們客服IM消息鏈路會(huì)涉及到三個(gè)核心端口:
1)發(fā)出方
2)IM網(wǎng)關(guān);
3)接收方。
以下將以客服發(fā)送一條消息到IM網(wǎng)關(guān)這個(gè)過(guò)程簡(jiǎn)單描述一下涉及到的技術(shù)點(diǎn),反之用戶側(cè)發(fā)送消息也是類似的。

從上述流程圖中可以看到:一條消息的旅程還是非常豐富的,當(dāng)然其中有一些細(xì)節(jié)點(diǎn)還沒(méi)有完全列舉出來(lái)。
例如:IM網(wǎng)關(guān)的超時(shí)重推機(jī)制、前端的異常處理(網(wǎng)絡(luò)異常、超時(shí)異常、重試無(wú)果等)。我們可以很清晰地看到當(dāng)客服開始輸入消息的時(shí)候就開始進(jìn)行通知對(duì)方正常輸入,觸發(fā)消息發(fā)送后需要進(jìn)行消息體的創(chuàng)建、排序、去重檢測(cè)、網(wǎng)絡(luò)檢測(cè)、聊天列表渲染、推入超時(shí)重試隊(duì)列、放入消息攔截器中統(tǒng)一進(jìn)行消息格式轉(zhuǎn)化并發(fā)送。
到這里只僅僅是完成了前端層面的發(fā)送工作而已,此時(shí)消息是否發(fā)送成功還是未知的,還需要監(jiān)聽消息的發(fā)送結(jié)果。如果在一定時(shí)間未收到響應(yīng)結(jié)果會(huì)進(jìn)行第二次消息的重發(fā),直到發(fā)送成功或到達(dá)最大重試次數(shù)就表示該消息的生命周期結(jié)束。
一旦收到消息的響應(yīng)結(jié)果就會(huì)對(duì)消息的狀態(tài)進(jìn)行更新(此時(shí)消息已完成了排序,不需要進(jìn)行二次排序),至此第一個(gè)環(huán)節(jié)就完成了處理,IM網(wǎng)關(guān)到客戶端也會(huì)有類似的處理過(guò)程。
縱觀整個(gè)消息發(fā)送以及接收鏈路,任何一個(gè)環(huán)節(jié)出現(xiàn)問(wèn)題都會(huì)導(dǎo)致消息發(fā)送出現(xiàn)問(wèn)題,就需要非常穩(wěn)定可靠的技術(shù)手段進(jìn)行保障,主要從以下幾個(gè)方面講解一下。
6、消息的可靠性傳遞
6.1概述
消息的可靠性傳遞確保了消息收發(fā)雙方信息的一致性。這也是我們?yōu)槭裁窗严⒖煽啃詡鬟f放在第一個(gè)進(jìn)行講解。
我們?cè)囅胍幌逻@樣一個(gè)場(chǎng)景:經(jīng)常有消息丟失,客服頻繁反饋,每次都要投入研發(fā)資源去排查問(wèn)題。這還是次要的,有可能因?yàn)橄⒌膩G失導(dǎo)致用戶體驗(yàn)的急劇下降,這就得不償失了。所以消息的可靠性傳遞是非常有必要的,而且也是必須的。
那么何為可靠性傳遞?至少要滿足3個(gè)方面,我們進(jìn)行詳細(xì)分享。
6.2消息的實(shí)時(shí)性
我們使用IM最重要的一方面就是希望對(duì)方能夠?qū)崟r(shí)接收到我們發(fā)送的消息并能夠給予回復(fù),這對(duì)于提升用戶體驗(yàn)尤為重要。如果不在乎實(shí)時(shí)性我們完全可以使用其他方式,例如郵件、寫信甚至飛鴿傳書…
一條消息發(fā)送給IM網(wǎng)關(guān),網(wǎng)關(guān)大致需要經(jīng)歷以下5個(gè)環(huán)節(jié)的處理:
1)驗(yàn)證消息:敏感詞驗(yàn)證、風(fēng)控送審(同步審核);
2)消息的存儲(chǔ):排序、去重驗(yàn)證等;
3)給發(fā)送消息方回復(fù)一個(gè)ACK響應(yīng)(成功、失敗);
4)把消息發(fā)送給接收方,如果存在多端登錄的場(chǎng)景,還需要保障消息多端同步;
5)超時(shí)重試、處理接收方返回的ACK等。
從消息的實(shí)時(shí)性的來(lái)說(shuō),沒(méi)有絕對(duì)的實(shí)時(shí),只能盡量?jī)?yōu)化。核心的處理邏輯都在IM網(wǎng)關(guān),無(wú)論是前端還是客戶端,處理過(guò)程都是非??斓模荚诤撩爰?jí)別。
我們IM網(wǎng)關(guān)是Go語(yǔ)言開發(fā)的,并發(fā)處理的能力也是非常高的,所以整個(gè)閉合鏈路的耗時(shí)還是非常低的。

6.3消息的可靠性
眾所周知,TCP本身就是具有可靠性的,但是它只能保障傳輸層可靠,而應(yīng)用層之間的可靠性并不能保證(可詳讀《為何基于TCP協(xié)議的移動(dòng)端IM仍然需要心跳?;顧C(jī)制?》、《從客戶端的角度來(lái)談?wù)勔苿?dòng)端IM的消息可靠性和送達(dá)機(jī)制》、《不為人知的網(wǎng)絡(luò)編程(十二):徹底搞懂TCP協(xié)議層的KeepAlive?;顧C(jī)制》)。我們后續(xù)會(huì)有針對(duì)性的專項(xiàng)文章進(jìn)行發(fā)表,本次就不再贅述。
那我們?cè)撊绾伪U蠎?yīng)用之間的可靠性呢?
可靠性的保障就是讓發(fā)送方知道接收方接收到了消息,這樣就表示消息成功傳遞了。
我們?cè)倩仡^看一下上面講述消息丟失的場(chǎng)景,消息丟失的問(wèn)題也是我們?cè)贗M消息研發(fā)過(guò)程中遇到的一個(gè)讓人頭疼的問(wèn)題,排查一個(gè)問(wèn)題需要投入的技術(shù)資源是非常巨大的,需要涉及到H5、IM網(wǎng)關(guān)、服務(wù)端以及客戶端,對(duì)于用戶以及客服的使用體驗(yàn)是非常差的。很簡(jiǎn)單的一個(gè)場(chǎng)景,用戶發(fā)了消息,客服沒(méi)有收到,沒(méi)有回復(fù)用戶,用戶以為客服故意不回復(fù),會(huì)影響到用戶的滿意度。
那這個(gè)問(wèn)題該如何解決呢?
大家可以看下《得物從0到1自研客服IM系統(tǒng)的技術(shù)實(shí)踐之路》,其中有講解過(guò),核心是參考TCP協(xié)議的ACK機(jī)制,實(shí)現(xiàn)一套基于業(yè)務(wù)層的ACK協(xié)議。
這里特別的要注意的是針對(duì)批量消息(客服刷新會(huì)話、新會(huì)話進(jìn)線等場(chǎng)景),我們采用的是批量ACK機(jī)制,如果每一個(gè)消息都回復(fù)ACK,成本會(huì)比較高。我們當(dāng)初是通過(guò)一個(gè)IM架構(gòu)升級(jí)技術(shù)專項(xiàng)協(xié)同各端完成了IM整體消息觸達(dá)實(shí)現(xiàn)0丟失,保證觸達(dá),滿足At least once(通過(guò)數(shù)據(jù)埋點(diǎn)驗(yàn)證后得到100%的觸達(dá)率)。上線后該場(chǎng)景符合預(yù)期效果,相應(yīng)的問(wèn)題排查投入也減少了至少70%+。
6.4消息的有序性
在開發(fā)IM過(guò)程中有這樣一個(gè)非常常見(jiàn)的場(chǎng)景,用戶問(wèn)A問(wèn)題后又問(wèn)題了B問(wèn)題,在客服側(cè)B問(wèn)題排到A問(wèn)題的前面,導(dǎo)致客服的回復(fù)也出現(xiàn)了錯(cuò)亂。
當(dāng)然這只是IM消息亂序的一種場(chǎng)景而已。諸如此類的還有很多。
消息亂序產(chǎn)生的原因有很多,例如發(fā)送文件后再立即發(fā)送消息,文件需要前端先上傳到OSS獲取到URL后再發(fā)送給用戶,上傳文件這個(gè)過(guò)程,用戶以及客服都是可以發(fā)送消息的,這種場(chǎng)景處理不好就極易出現(xiàn)消息亂序。
不做IM是真不會(huì)想到客服操作的效率會(huì)有多高,之前在處理消息亂序問(wèn)題的時(shí)候有遇到客服連續(xù)發(fā)送了2條消息,間隔只有300毫秒,這種高頻密集的操作場(chǎng)景在客服的工作場(chǎng)景下是持續(xù)性的。
看似一個(gè)亂序問(wèn)題,不考慮清楚用戶群體、極限場(chǎng)景、臨界值等都不會(huì)徹底解決掉這個(gè)問(wèn)題。
再說(shuō)回我們客服IM,我們是如何處理消息排序的呢?
在整個(gè)開發(fā)過(guò)程也是比較曲折的,最終是以IM網(wǎng)關(guān)維護(hù)的Seq為準(zhǔn),然后返回到發(fā)送方,發(fā)送再根據(jù)消息序號(hào)進(jìn)行排序,確保發(fā)送方和接收方消息的排序是一致的。
前端處理的流程如下:

6.5消息的冪等性
說(shuō)到消息的冪等性,我們要思考一個(gè)問(wèn)題,為什么會(huì)收到多條(>1)相同的消息呢?
肯定是發(fā)送方重復(fù)發(fā)送導(dǎo)致的,那在什么場(chǎng)景下會(huì)重復(fù)發(fā)送?
前面剛講過(guò)應(yīng)用層的ACK機(jī)制,如果沒(méi)有收到對(duì)方的ACK,會(huì)在超時(shí)時(shí)間到達(dá)后繼續(xù)重復(fù)發(fā)送直到最大重試次數(shù)。參考下面的截圖會(huì)更容易理解,只是模擬消息重試,真實(shí)場(chǎng)景中執(zhí)行頻次肯定要比這個(gè)時(shí)間更久一些。

既然要保證消息的可靠性,消息的重復(fù)就是無(wú)法避免的。就有可能出現(xiàn)消息冪等性問(wèn)題。
那怎么解決呢?
我們是利用消息的Message ID做去重的,這里會(huì)涉及到一個(gè)性能問(wèn)題,排序、去重以及風(fēng)控信息驗(yàn)證等都需要一定的計(jì)算成本,如何保證處理過(guò)程系統(tǒng)不卡頓是一個(gè)核心問(wèn)題。
想要了解我們客服IM是如何做的,請(qǐng)繼續(xù)向下看。
7、消息處理的卡頓優(yōu)化策略
7.1概述
我們來(lái)想一下為什么會(huì)出現(xiàn)卡頓?
什么樣的場(chǎng)景才能夠被視為卡頓呢?
我們一般都會(huì)說(shuō)是因?yàn)樵?6ms內(nèi)無(wú)法完成渲染導(dǎo)致的。那么為什么需要在16ms內(nèi)完成呢?
這里我們就要了解一下刷新率(RefreshRate)與幀率(FrameRate):
1)刷新率:指的是屏幕每秒刷新的次數(shù),是針對(duì)硬件而言的。瀏覽器刷新率都在60Hz(屏幕每秒鐘刷新60次);
2)幀率:是每秒繪制的幀數(shù),是針對(duì)軟件而言的。通常只要幀率與刷新率保持一致,我們看到的畫面就是流暢的。所以幀率在60FPS時(shí)我們就不會(huì)感覺(jué)到卡。
如果:幀率為每秒鐘60幀,而屏幕刷新率為30Hz,那么就會(huì)出現(xiàn)屏幕上半部分還停留在上一幀的畫面,屏幕的下半部分渲染出來(lái)的就是下一幀的畫面,這種情況被稱為畫面撕裂。
相反:如果幀率為每秒鐘30幀,屏幕刷新率為60Hz,那么就會(huì)出現(xiàn)相連兩幀顯示的是同一畫面,這就出現(xiàn)了卡頓。所以單方面的提升幀率或者刷新率是沒(méi)有意義的,需要兩者同時(shí)進(jìn)行提升。瀏覽器都采用的60Hz的刷新率,為了使幀率也能達(dá)到60FPS,那么就要求在16.67ms內(nèi)要完成一幀的繪制(1000ms/60Frame = 16.666ms / Frame)。
IM消息處理中出現(xiàn)卡頓的情況非常常見(jiàn),到一定的量級(jí)都是一個(gè)很難避免的問(wèn)題。對(duì)比我們經(jīng)常使用電腦,打開多個(gè)瀏覽器頁(yè)簽,稍微時(shí)間長(zhǎng)點(diǎn)不關(guān)機(jī)重啟,也會(huì)感覺(jué)到卡頓。但對(duì)于IM消息處理還是有很多方式進(jìn)行優(yōu)化的。
主要涉及以下幾方面的優(yōu)化策略,我來(lái)展開討論。
7.2異步處理
眾所周知JS是單線程的,所以采用異步處理機(jī)制可以將優(yōu)先級(jí)低的任務(wù)推入異步任務(wù)隊(duì)列,讓出主線程給優(yōu)先級(jí)高的任務(wù)。
比如:客服在輸入完消息后需要立即顯示的聊天頁(yè)面,如果存在短暫的不顯示,會(huì)被認(rèn)為是系統(tǒng)卡頓了,所以發(fā)送消息的優(yōu)先級(jí)是高于接收消息的。
我們對(duì)各場(chǎng)景任務(wù)優(yōu)先級(jí)做了區(qū)分,低優(yōu)先級(jí)的任務(wù)都通過(guò)異步的方式進(jìn)行處理。
7.3分段加載
這里主要針對(duì)聊天消息列表,對(duì)于大量消息的會(huì)話處理,只渲染可視區(qū)域的消息降低瀏覽器的負(fù)擔(dān),提升響應(yīng)速度。
列表優(yōu)化的方案有很多,如下。
1)方案 1:
使用定時(shí)器setTimeout來(lái)實(shí)現(xiàn)分批渲染。
這種方式我們一般不推薦,因?yàn)樵趕etTimeout中對(duì)DOM進(jìn)行操作,必須要等到屏幕下次繪制時(shí)才能更新到屏幕上,如果兩者步調(diào)不一致,就可能導(dǎo)致中間某一幀的操作被跨越過(guò)去,而直接更新下一幀的元素,從而導(dǎo)致丟幀現(xiàn)象。
2)方案 2:
采用requestAnimationFrame。相比之下,requestAnimationFrame的優(yōu)勢(shì)還是非常明顯的。
主要體現(xiàn)在以下幾個(gè)方面:
1)requestAnimationFrame會(huì)把每一幀中的所有DOM操作集中起來(lái),再一次重繪或回流中就完成,并且重繪或回流的時(shí)間間隔緊緊跟隨瀏覽器的刷新頻率;
2)在隱藏或不可見(jiàn)的元素中,requestAnimationFrame將不會(huì)進(jìn)行重繪或回流,這當(dāng)然就意味著更少的CPU、GPU和內(nèi)存使用量;
3)requestAnimationFrame是由瀏覽器專門為動(dòng)畫提供的API,在運(yùn)行時(shí)瀏覽器會(huì)自動(dòng)優(yōu)化方法的調(diào)用,并且如果頁(yè)面不是激活狀態(tài)下的話,動(dòng)畫會(huì)自動(dòng)暫停,有效節(jié)省了CPU開銷;
4)與setTimeout相比,requestAnimationFrame最大的優(yōu)勢(shì)是由系統(tǒng)來(lái)決定回調(diào)函數(shù)的執(zhí)行時(shí)機(jī);
5)requestAnimationFrame的步伐跟著系統(tǒng)的刷新步伐走。它能保證回調(diào)函數(shù)在屏幕每一次的刷新間隔中只被執(zhí)行一次,這樣就不會(huì)引起丟幀現(xiàn)象。
3)方案 3:
采用IntersectionObserver。
IntersectionObserver接口(從屬于Intersection Observer API)為開發(fā)者提供了一種可以異步監(jiān)聽目標(biāo)元素與其祖先或視窗(viewport)交叉狀態(tài)的手段。祖先元素與視窗(viewport)被稱為根(root)。

可以看到,交叉了就是說(shuō)明當(dāng)前元素在視窗里,當(dāng)前就是可見(jiàn)的了。是代替監(jiān)聽滾動(dòng)加載的不錯(cuò)方案。
當(dāng)然還有其他方案,還是要根據(jù)實(shí)際的業(yè)務(wù)場(chǎng)景選擇合適的方案,IM消息分段加載的難點(diǎn)在于消息的不定高(多種不同類型的消息),計(jì)算成本還是有一些昂貴的。所以優(yōu)化還是要驗(yàn)證一下臨界值的,有時(shí)候優(yōu)化不一定會(huì)有效。
7.4消息遍歷
上面我們講到消息排序、去重以及消息狀態(tài)更新等等,多個(gè)會(huì)話大量的聊天消息,如果處理不當(dāng),卡頓是必現(xiàn)的。
可以先看一下我們優(yōu)化之前的處理流程,采用的是第三方的SDK,一堆for循環(huán),消息量大一些基本卡住沒(méi)反應(yīng)了。

那我們是如何處理這個(gè)問(wèn)題的呢?
基于現(xiàn)有的業(yè)務(wù)場(chǎng)景重寫三方SDK,將會(huì)話維護(hù)成獨(dú)立的實(shí)例,核心算法就是采用二分法。
感興趣的同學(xué)可以看之前的這篇文章《得物從0到1自研客服IM系統(tǒng)的技術(shù)實(shí)踐之路》,講述得比較詳細(xì)。重寫了IM SDK之后,客服再也沒(méi)有反饋過(guò)聊天相關(guān)的卡頓,聊天首響提升了20%,成果還是比較顯著的。
8、消息安全方面的考慮
在IM系統(tǒng)中,消息的安全性是非常重要,開發(fā)同學(xué)需要具備較強(qiáng)的安全意識(shí),將安全融入到開發(fā)流程中,增強(qiáng)系統(tǒng)的安全性和健壯性。
消息安全性方面的事情我們做了很多,這里也不再詳細(xì)講解了,有興趣可以讀讀下面的文章:
《即時(shí)通訊安全篇(二):探討組合加密算法在IM中的應(yīng)用》
《即時(shí)通訊安全篇(十):IM聊天系統(tǒng)安全手段之通信連接層加密技術(shù)》
《即時(shí)通訊安全篇(十一):IM聊天系統(tǒng)安全手段之傳輸內(nèi)容端到端加密技術(shù)》
《微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解》
《基于Netty的IM聊天加密技術(shù)學(xué)習(xí):一文理清常見(jiàn)的加密概念、術(shù)語(yǔ)等》
《手把手教你為基于Netty的IM生成自簽名SSL/TLS證書》
9、消息發(fā)送和接收的延遲
消息發(fā)送和接收的延遲直接影響用戶的使用體驗(yàn)和溝通效率,在上面我們已經(jīng)分析過(guò)一條消息的旅程,出現(xiàn)延遲的原因也比較好分析。
主要有以下4點(diǎn):
1)網(wǎng)絡(luò)延遲:IM消息的發(fā)送和接收是以長(zhǎng)鏈接的方式進(jìn)行網(wǎng)絡(luò)傳輸?shù)?,而網(wǎng)絡(luò)傳輸過(guò)程中會(huì)產(chǎn)生一定的延遲。如果網(wǎng)絡(luò)延遲高,就會(huì)導(dǎo)致消息發(fā)送和接收較慢;
2)系統(tǒng)負(fù)載:客服在一對(duì)多的情況下,多個(gè)用戶同時(shí)在線,系統(tǒng)需要處理大量的消息和請(qǐng)求,導(dǎo)致系統(tǒng)響應(yīng)速度較慢,這會(huì)對(duì)客服的體驗(yàn)造成影響;
3)前端延遲:需要經(jīng)過(guò)本地消息隊(duì)列、緩存等處理,可能導(dǎo)致消息的延遲;
4)消息編碼和解碼:部分消息需要對(duì)數(shù)據(jù)進(jìn)行編碼和解碼,也會(huì)消耗一定的時(shí)間,從而導(dǎo)致延遲。
既然能分析出原因,我們就能對(duì)癥下藥,可以通過(guò)一些優(yōu)化策略來(lái)降低發(fā)送和接收的延遲。
目前規(guī)劃從以下2個(gè)方面來(lái)進(jìn)行優(yōu)化。
1)前端方面:
延遲主要在消息的處理和編解碼方面,目前我們IM消息的數(shù)據(jù)格式是JSON,存在序列化和反序列化的過(guò)程,這里我們會(huì)采用ProtoBuf 替換JSON,目前已完成了相關(guān)技術(shù)調(diào)研和測(cè)試驗(yàn)證。我們簡(jiǎn)單來(lái)看一下ProtoBuf(Protocol Buffers)和 JSON 處理耗時(shí)的對(duì)比。
編碼時(shí)間:ProtoBuf 的編碼時(shí)間比 JSON 快得多,因?yàn)?ProtoBuf 的編碼是二進(jìn)制的,不需要進(jìn)行編碼轉(zhuǎn)換以及無(wú)需進(jìn)行冗余類型的轉(zhuǎn)換。相對(duì)而言,JSON 的編碼時(shí)間較慢。
解碼時(shí)間:相比編碼,ProtoBuf 的解碼效率要稍微低一些。但是,由于 ProtoBuf 的優(yōu)勢(shì)在數(shù)據(jù)量大、結(jié)構(gòu)復(fù)雜的情況下更為明顯,對(duì)于小型數(shù)據(jù)解碼時(shí),兩者的效率差異可能不太明顯。
有關(guān)Profobuf的更多資料,可以詳讀以下文章:
《IM通訊協(xié)議專題學(xué)習(xí)(一):Protobuf從入門到精通,一篇就夠!》
《IM通訊協(xié)議專題學(xué)習(xí)(二):快速理解Protobuf的背景、原理、使用、優(yōu)缺點(diǎn)》
《IM通訊協(xié)議專題學(xué)習(xí)(三):由淺入深,從根上理解Protobuf的編解碼原理》
《IM通訊協(xié)議專題學(xué)習(xí)(四):從Base64到Protobuf,詳解Protobuf的數(shù)據(jù)編碼原理》
《IM通訊協(xié)議專題學(xué)習(xí)(五):Protobuf到底比JSON快幾倍?全方位實(shí)測(cè)!》
《IM通訊協(xié)議專題學(xué)習(xí)(六):手把手教你如何在Android上從零使用Protobuf》
《IM通訊協(xié)議專題學(xué)習(xí)(七):手把手教你如何在NodeJS中從零使用Protobuf》
《IM通訊協(xié)議專題學(xué)習(xí)(八):金蝶隨手記團(tuán)隊(duì)的Protobuf應(yīng)用實(shí)踐(原理篇)》
《IM通訊協(xié)議專題學(xué)習(xí)(九):手把手教你如何在iOS上從零使用Protobuf》
2)網(wǎng)絡(luò)延遲:
網(wǎng)絡(luò)延遲我們很難控制,但是可以通過(guò)降低消息傳輸體積進(jìn)行相關(guān)優(yōu)化。
剛講了Protobuf 替換JSON,Protobuf是二進(jìn)制格式,比JSON格式更加緊湊,能夠使數(shù)據(jù)包大小大幅度減小,在網(wǎng)絡(luò)傳輸中能夠減少帶寬占用和流量費(fèi)用。
在IM系統(tǒng)中,由于用戶數(shù)量龐大,消息發(fā)送頻繁,在數(shù)據(jù)占用和網(wǎng)絡(luò)帶寬方面是一個(gè)巨大的問(wèn)題,使用ProtoBuf能夠顯著地減少網(wǎng)絡(luò)帶寬消耗,提高系統(tǒng)的性能。
還有一方面就是消息壓縮,但是壓縮的深度和壓縮算法需要慎重選擇、驗(yàn)證。
所以使用ProtoBuf格式代替JSON格式基本可以解掉一大半延遲問(wèn)題,也是接下來(lái)IM優(yōu)化的一個(gè)方向。
10、坐席體驗(yàn)和交互的考慮
說(shuō)到坐席體驗(yàn)和交互方面,我們還是積累了不少經(jīng)驗(yàn)的。不僅僅是IM,體驗(yàn)和交互是所有產(chǎn)品都無(wú)法繞開的一個(gè)話題。
自從做IM以來(lái),體驗(yàn)可謂是鞭策我們不斷前進(jìn)的動(dòng)力,卡頓是一直環(huán)繞在我耳邊的一個(gè)話題。
客服理解的卡頓和我們正常理解的卡頓還是有點(diǎn)不一樣的,前期我們也以為是系統(tǒng)卡住導(dǎo)致無(wú)法使用了,類似掉幀的場(chǎng)景。
實(shí)際卻不是:
1)接口請(qǐng)求慢了;
2)有錯(cuò)誤的Tip提示;
3)頁(yè)面切換有短暫空白顯示;
4)輸入消息回車后消息未立刻顯示到聊天頁(yè)面;
5)圖片上傳的Loading提示等等。
以上都會(huì)被歸為卡頓。
針對(duì)這些方面:我們也是不斷的進(jìn)行職場(chǎng)調(diào)研、數(shù)據(jù)分析、優(yōu)化,客服的滿意度提升到了18%??赡茉诖蠹铱磥?lái)做了這么久提升18%并不是一個(gè)比較好的數(shù)據(jù),但是針對(duì)客服域,提升18%也是一個(gè)相對(duì)比較難逾越的數(shù)據(jù)了。
主要的原因在2個(gè)方面:
1)第一個(gè)方面是很多客服都是3個(gè)月以內(nèi)入職的,對(duì)于我們做的一些功能優(yōu)化對(duì)比體驗(yàn)是無(wú)法感知或缺少功能使用對(duì)比的;
2)第二個(gè)方面是很多一線客服都來(lái)自一線大廠的客服服務(wù)團(tuán)隊(duì)。
其實(shí)反過(guò)來(lái)想一下,這也是一種正向的驅(qū)動(dòng),至少我們每次調(diào)研都能收集到新的反饋,同更加成熟、優(yōu)秀產(chǎn)品的體驗(yàn)差距。
體驗(yàn)不是一蹴而就的,不要想著一下子就做到位,一個(gè)優(yōu)秀的用戶體驗(yàn)和交互設(shè)計(jì)需要始終與用戶需求和反饋相結(jié)合,并不斷改進(jìn)和完善。在實(shí)際設(shè)計(jì)和開發(fā)過(guò)程中,需要進(jìn)行不斷的測(cè)試和優(yōu)化,以確保系統(tǒng)的質(zhì)量和可接受性。同時(shí),需要與用戶進(jìn)行積極的溝通和反饋,以便更好地理解用戶需求和意見(jiàn)。這一點(diǎn)我們之前是做的不夠好的,尤其是新版本的推廣,系統(tǒng)的易用性并未達(dá)到客服的期望,也是我們后期需要持續(xù)改進(jìn)的一個(gè)方面。
體驗(yàn)是以絕大數(shù)用戶需求為核心的,不能僅僅為了一小部分用戶而去犧牲其他用戶的使用體驗(yàn),尤其不能因?yàn)槟骋粋€(gè)用戶的反饋意見(jiàn)而做出過(guò)多的改變或者犧牲其他用戶的利益。體驗(yàn)優(yōu)化過(guò)程的不妥協(xié)也是非常重要的策略,在體驗(yàn)優(yōu)化過(guò)程中,必須保持理性和客觀,根據(jù)用戶調(diào)研和數(shù)據(jù)分析進(jìn)行合理的權(quán)衡和決策,以實(shí)現(xiàn)最佳的用戶體驗(yàn)。
一些小細(xì)節(jié)的優(yōu)化也可以起到事半功倍的效果,在IM系統(tǒng)中,一些細(xì)節(jié)的優(yōu)化包括:及時(shí)的消息提示、清晰的消息展示、精確的消息發(fā)送時(shí)間等等。這些小細(xì)節(jié)的優(yōu)化可以直接提高客服的使用效率和體驗(yàn),從而提高客服滿意度。IM的體驗(yàn)優(yōu)化我們會(huì)一直做下去,有志者事竟成。
11、后續(xù)規(guī)劃
上述技術(shù)和思考的細(xì)節(jié)中有講到消息的可靠性傳遞、卡頓優(yōu)化處理、安全性、效率以及體驗(yàn)等。
接下來(lái)的一段時(shí)間我們還是以這幾個(gè)方面為主線進(jìn)行,持續(xù)優(yōu)化、完善IM相關(guān)能力。
主要考慮以下幾個(gè)方面的規(guī)劃:
1)體驗(yàn)優(yōu)化:體驗(yàn)是我們一如既往要做的事情,會(huì)持續(xù)挖掘視覺(jué)、交互等層面的優(yōu)化點(diǎn),從細(xì)節(jié)入手,比如:顏色搭配,按鍵選擇等,提供良好的坐席體驗(yàn);
2)ProtoBuf 替換JSON:降低消息編碼時(shí)間、提升解碼效率、減少數(shù)據(jù)包體積、減少網(wǎng)絡(luò)帶寬消耗,提高系統(tǒng)的性能;
3)消息壓縮:尤其是針對(duì)歷史消息、批量消息,使用壓縮技術(shù),可以有效的減少數(shù)據(jù)包的體積;
4)功能擴(kuò)展:持續(xù)完善機(jī)器人消息類型,尤其是針對(duì)售前導(dǎo)購(gòu)、坐席輔助。逐步支持消息引用、標(biāo)記等功能;
5)多語(yǔ)言能力支持:雖然目前還沒(méi)有接入國(guó)際化業(yè)務(wù),但在設(shè)計(jì)層面還是要具備快速擴(kuò)展的能力。
上述幾個(gè)方面我們會(huì)優(yōu)先去做重要且緊急的技術(shù)改造,并不會(huì)一味的創(chuàng)新、優(yōu)化,還是會(huì)以業(yè)務(wù)為主,緊緊圍繞業(yè)務(wù)和坐席體驗(yàn)展開。
12、本文小結(jié)
客服發(fā)送一條消息在IM應(yīng)用中看似簡(jiǎn)單,背后需要考慮的技術(shù)細(xì)節(jié)點(diǎn)是很多的。首先,這需要考慮到消息的發(fā)送機(jī)制和可靠性。即使是一條簡(jiǎn)單的消息,也需要經(jīng)過(guò)一系列的加密、編碼、傳輸、安全合規(guī)等等處理才能被成功接收。
最重要的是要考慮到數(shù)據(jù)實(shí)時(shí)性的問(wèn)題,各種極限場(chǎng)景下的操作,客服發(fā)送的消息需要被及時(shí)展示到聊天頁(yè)并傳輸給用戶,客服同學(xué)在一對(duì)多的場(chǎng)景下工作,需要確保各會(huì)話消息不會(huì)出現(xiàn)不一致(丟失、重復(fù)),還有消息攔截和異常情況等問(wèn)題。
因此,客服發(fā)送一條消息不僅需要技術(shù)能力和數(shù)據(jù)處理能力,還需要思考坐席體驗(yàn)和數(shù)據(jù)實(shí)時(shí)性等方面的問(wèn)題。開發(fā)過(guò)程中需要細(xì)致入微地處理各種問(wèn)題并持續(xù)優(yōu)化,從而為客服提供一個(gè)穩(wěn)定、流暢、安全、友好的IM應(yīng)用。
13、參考文章
[1]?得物基于Electron開發(fā)客服IM桌面端的技術(shù)實(shí)踐
[2]?得物從0到1自研客服IM系統(tǒng)的技術(shù)實(shí)踐之路
[3]?為何基于TCP協(xié)議的移動(dòng)端IM仍然需要心跳?;顧C(jī)制?
[4]?從客戶端的角度來(lái)談?wù)勔苿?dòng)端IM的消息可靠性和送達(dá)機(jī)制
[5]?不為人知的網(wǎng)絡(luò)編程(十二):徹底搞懂TCP協(xié)議層的KeepAlive?;顧C(jī)制
[6]?微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解
[7]?基于Netty的IM聊天加密技術(shù)學(xué)習(xí):一文理清常見(jiàn)的加密概念、術(shù)語(yǔ)等
[8]?IM通訊協(xié)議專題學(xué)習(xí)(一):Protobuf從入門到精通,一篇就夠!
[9]?IM通訊協(xié)議專題學(xué)習(xí)(二):快速理解Protobuf的背景、原理、使用、優(yōu)缺點(diǎn)
[10]?IM通訊協(xié)議專題學(xué)習(xí)(三):由淺入深,從根上理解Protobuf的編解碼原理
[11]?請(qǐng)問(wèn)有人知道語(yǔ)音留言聊天的主流實(shí)現(xiàn)方式嗎?
[12]?IM消息送達(dá)保證機(jī)制實(shí)現(xiàn)(一):保證在線實(shí)時(shí)消息的可靠投遞
[13]?IM消息送達(dá)保證機(jī)制實(shí)現(xiàn)(二):保證離線消息的可靠投遞
[14]?如何保證IM實(shí)時(shí)消息的“時(shí)序性”與“一致性”?
[15]?一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(下篇):可靠性、有序性、弱網(wǎng)優(yōu)化等
[16]?融云技術(shù)分享:全面揭秘億級(jí)IM消息的可靠投遞機(jī)制
(本文已同步發(fā)布于:http://www.52im.net/thread-4483-1-1.html)