在企業客服場景中,客服發送一條消息的背后,需要考慮網絡通信、前端展示、后端存儲以及安全性等多個方面的技術支持,單從前端層面來說,就需要考慮到消息的顯示、狀態更新、穩定傳輸以及極限操作消息不卡頓等場景,隨著IM系統的不斷更新迭代,已經實現了從外采到自研再到一站式全場景工作臺的搭建,我們能夠很明顯地感知到客服對于IM的體驗要求越來越高了,因此客服發送一條消息背后所涉及的技術和思考也越來越重要。本文將探秘客服發送一條消息背后的技術和思考,幫助大家了解如何在IM聊天場景中提供高效、安全、可靠和良好的用戶體驗。
IM聊天消息是客服和用戶之間最快速、最直觀、最高效的雙向溝通方式之一。IM聊天的重要性體現在以下幾個方面:
即時響應:及時地解答用戶咨詢的問題,更快捷的服務用戶,提高用戶滿意度。
個性化互動:可以根據用戶的需求快速做出個性化回應,從而更好地滿足用戶需求。
數據處理和分析:通過對IM聊天消息的處理分析,可以洞察用戶需求、用戶行為,幫助改進服務質量。
綜上,IM聊天消息的重要性在于提高用戶滿意度、提高客服作業效率,這也意味著IM消息的可靠、高效、安全尤為重要,接下來本文就從前端視角對客服發送一條消息背后的技術和思考進行詳細的講述。
以下是客服IM消息發展的歷程,列舉的都是核心技術專項的里程碑節點。
圖片
在這個過程中,我們積累了一定的經驗和技能,同時也遇到了各種各樣的問題和挑戰。比如:消息丟失、消息發送失敗、消息重復、消息亂序等等方面的問題,針對這些問題我們也都通過技術專項的方式去逐個解決并達到了預期效果,我們相信,隨著技術的不斷發展和創新,我們可以更好地提供更加高效便捷的服務。
站在用戶/客服角度,發送消息不就是輸入消息后點擊回車鍵或點擊發送按鈕就完成了嗎,看似非常簡單,但是從開始輸入消息到對方收到消息這個過程實際上有非常強大的技術在高效、穩定支撐。我們客服IM消息鏈路會涉及到三個核心端口,發出方、IM網關以及接收方。以下將以客服發送一條消息到IM網關這個過程簡單描述一下涉及到的技術點,反之用戶側發送消息也是類似的。
圖片
從上述流程圖中可以看到一條消息的旅程還是非常豐富的,當然其中有一些細節點還沒有完全列舉出來,例如:IM網關的超時重推機制、前端的異常處理(網絡異常、超時異常、重試無果等)。我們可以很清晰地看到當客服開始輸入消息的時候就開始進行通知對方正常輸入,觸發消息發送后需要進行消息體的創建、排序、去重檢測、網絡檢測、聊天列表渲染、推入超時重試隊列、放入消息攔截器中統一進行消息格式轉化并發送,到這里只僅僅是完成了前端層面的發送工作而已,此時消息是否發送成功還是未知的,還需要監聽消息的發送結果,如果在一定時間未收到響應結果會進行第二次消息的重發,直到發送成功或到達最大重試次數就表示該消息的生命周期結束。一旦收到消息的響應結果就會對消息的狀態進行更新(此時消息已完成了排序,不需要進行二次排序),至此第一個環節就完成了處理,IM網關到客戶端也會有類似的處理過程。
縱觀整個消息發送以及接收鏈路,任何一個環節出現問題都會導致消息發送出現問題,就需要非常穩定可靠的技術手段進行保障,主要從以下幾個方面講解一下。
消息的可靠性傳遞確保了消息收發雙方信息的一致性。這也是我們為什么把消息可靠性傳遞放在第一個進行講解。我們試想一下這樣一個場景,經常有消息丟失,客服頻繁反饋,每次都要投入研發資源去排查問題,這還是次要的,有可能因為消息的丟失導致用戶體驗的急劇下降,這就得不償失了。所有消息的可靠性傳遞是非常有必要的,而且也是必須的。那么何為可靠性傳遞?至少要滿足3個方面:
我們使用IM最重要的一方面就是希望對方能夠實時接收到我們發送的消息并能夠給予回復,這對于提升用戶體驗尤為重要。如果不在乎實時性我們完全可以使用其他方式,例如郵件、寫信甚至飛鴿傳書…
一條消息發送給IM網關,網關大致需要經歷以下5個環節的處理:
驗證消息:敏感詞驗證、風控送審(同步審核)
消息的存儲:排序、去重驗證等
給發送消息方回復一個ACK響應(成功、失敗)
把消息發送給接收方,如果存在多端登錄的場景,還需要保障消息多端同步
超時重試、處理接收方返回的ACK等
從消息的實時性的來說,沒有絕對的實時,只能盡量優化。核心的處理邏輯都在IM網關,無論是前端還是客戶端,處理過程都是非常快的,都在毫秒級別。我們IM網關是Go語言開發的,并發處理的能力也是非常高的,所以整個閉合鏈路的耗時還是非常低的。
圖片
眾所周知,TCP本身就是具有可靠性的,但是它只能保障傳輸層可靠,而應用層之間的可靠性并不能保證,我們后續會有針對性的專項文章進行發表,本次就不再贅述。
那我們該如何保障應用之間的可靠性呢? 可靠性的保障就是讓發送方知道接收方接收到了消息,這樣就表示消息成功傳遞了。我們再回頭看一下上面講述消息丟失的場景,消息丟失的問題也是我們在IM消息研發過程中遇到的一個讓人頭疼的問題,排查一個問題需要投入的技術資源是非常巨大的,需要涉及到H5、IM網關、服務端以及客戶端,對于用戶以及客服的使用體驗是非常差的。很簡單的一個場景,用戶發了消息,客服沒有收到,沒有回復用戶,用戶以為客服故意不回復,會影響到用戶的滿意度。
那這個問題該如何解決呢?大家可以看下得物客服IM消息通信SDK自研之路,其中有講解過,核心是參考TCP協議的ACK機制,實現一套基于業務層的ACK協議。這里特別的要注意的是針對批量消息(客服刷新會話、新會話進線等場景),我們采用的是批量ACK機制,如果每一個消息都回復ACK,成本會比較高。我們當初是通過一個IM架構升級技術專項協同各端完成了IM整體消息觸達實現0丟失,保證觸達,滿足At least once(通過數據埋點驗證后得到100%的觸達率)。上線后該場景符合預期效果,相應的問題排查投入也減少了至少70%+。
在開發IM過程中有這樣一個非常常見的場景,用戶問A問題后又問題了B問題,在客服側B問題排到A問題的前面,導致客服的回復也出現了錯亂。當然這只是IM消息亂序的一種場景而已。諸如此類的還有很多。消息亂序產生的原因有很多,例如發送文件后再立即發送消息,文件需要前端先上傳到OSS獲取到URL后再發送給用戶,上傳文件這個過程,用戶以及客服都是可以發送消息的,這種場景處理不好就極易出現消息亂序。
不做IM是真不會想到客服操作的效率會有多高,之前在處理消息亂序問題的時候有遇到客服連續發送了2條消息,間隔只有300毫秒,這種高頻密集的操作場景在客服的工作場景下是持續性的。
看似一個亂序問題,不考慮清楚用戶群體、極限場景、臨界值等都不會徹底解決掉這個問題。
再說回我們客服IM,我們是如何處理消息排序的呢?在整個開發過程也是比較曲折的,最終是以IM網關維護的Seq為準,然后返回到發送方,發送再根據消息序號進行排序,確保發送方和接收方消息的排序是一致的。前端處理的流程如下:
說到消息的冪等性,我們要思考一個問題,為什么會收到多條(>1)相同的消息呢?肯定是發送方重復發送導致的,那在什么場景下會重復發送?前面剛講過應用層的ACK機制,如果沒有收到對方的ACK,會在超時時間到達后繼續重復發送直到最大重試次數。參考下面的截圖會更容易理解,只是模擬消息重試,真實場景中執行頻次肯定要比這個時間更久一些。
圖片
既然要保證消息的可靠性,消息的重復就是無法避免的。就有可能出現消息冪等性問題。那怎么解決呢?我們是利用消息的Message ID做去重的,這里會涉及到一個性能問題,排序、去重以及風控信息驗證等都需要一定的計算成本,如何保證處理過程系統不卡頓是一個核心問題。想要了解我們客服IM是如何做的,請繼續向下看。
我們來想一下為什么會出現卡頓?什么樣的場景才能夠被視為卡頓呢?我們一般都會說是因為在16ms內無法完成渲染導致的。那么為什么需要在16ms內完成呢?這里我們就要了解一下刷新率(RefreshRate)與幀率(FrameRate)。
如果幀率為每秒鐘60幀,而屏幕刷新率為30Hz,那么就會出現屏幕上半部分還停留在上一幀的畫面,屏幕的下半部分渲染出來的就是下一幀的畫面,這種情況被稱為畫面撕裂。相反,如果幀率為每秒鐘30幀,屏幕刷新率為60Hz,那么就會出現相連兩幀顯示的是同一畫面,這就出現了卡頓。所以單方面的提升幀率或者刷新率是沒有意義的,需要兩者同時進行提升。瀏覽器都采用的60Hz的刷新率,為了使幀率也能達到60FPS,那么就要求在16.67ms內要完成一幀的繪制(1000ms/60Frame = 16.666ms / Frame)。
IM消息處理中出現卡頓的情況非常常見,到一定的量級都是一個很難避免的問題,對比我們經常使用電腦,打開多個瀏覽器頁簽,稍微時間長點不關機重啟,也會感覺到卡頓,但對于IM消息處理還是有很多方式進行優化的,主要涉及以下幾方面的優化策略:
眾所周知JS是單線程的,所以采用異步處理機制可以將優先級低的任務推入異步任務隊列,讓出主線程給優先級高的任務。比如:客服在輸入完消息后需要立即顯示的聊天頁面,如果存在短暫的不顯示,會被認為是系統卡頓了,所以發送消息的優先級是高于接收消息的。我們對各場景任務優先級做了區分,低優先級的任務都通過異步的方式進行處理。
這里主要針對聊天消息列表,對于大量消息的會話處理,只渲染可視區域的消息降低瀏覽器的負擔,提升響應速度。列表優化的方案有很多。如下:
方案1:使用定時器setTimeout來實現分批渲染,這種方式我們一般不推薦,因為在setTimeout中對DOM進行操作,必須要等到屏幕下次繪制時才能更新到屏幕上,如果兩者步調不一致,就可能導致中間某一幀的操作被跨越過去,而直接更新下一幀的元素,從而導致丟幀現象。
方案2:采用requestAnimationFrame,相比之下,requestAnimationFrame的優勢還是非常明顯的,主要體現在以下幾個方面:
方案3:采用IntersectionObserver,IntersectionObserver接口(從屬于Intersection Observer API)為開發者提供了一種可以異步監聽目標元素與其祖先或視窗(viewport)交叉狀態的手段。祖先元素與視窗(viewport)被稱為根(root)。
圖片
可以看到,交叉了就是說明當前元素在視窗里,當前就是可見的了。是代替監聽滾動加載的不錯方案。
當然還有其他方案,還是要根據實際的業務場景選擇合適的方案,IM消息分段加載的難點在于消息的不定高(多種不同類型的消息),計算成本還是有一些昂貴的。所以優化還是要驗證一下臨界值的,有時候優化不一定會有效。
上面我們講到消息排序、去重以及消息狀態更新等等,多個會話大量的聊天消息,如果處理不當,卡頓是必現的,可以先看一下我們優化之前的處理流程,采用的是第三方的SDK,一堆for循環,消息量大一些基本卡住沒反應了。
圖片
那我們是如何處理這個問題的呢?基于現有的業務場景重寫三方SDK,將會話維護成獨立的實例,核心算法就是采用二分法。感興趣的同學可以看之前的這篇文章 得物客服IM消息通信SDK自研之路,講述得比較詳細。重寫了IM SDK之后,客服再也沒有反饋過聊天相關的卡頓,聊天首響提升了20%,成果還是比較顯著的。
在IM系統中,消息的安全性是非常重要,開發同學需要具備較強的安全意識,將安全融入到開發流程中,增強系統的安全性和健壯性。消息安全性方面的事情我們做了很多,這里也不再詳細講解了。
消息發送和接收的延遲直接影響用戶的使用體驗和溝通效率,在上面我們已經分析過一條消息的旅程,出現延遲的原因也比較好分析,主要有以下4點:
既然能分析出原因,我們就能對癥下藥,可以通過一些優化策略來降低發送和接收的延遲,目前規劃從以下2個方面來進行優化:
編碼時間:ProtoBuf 的編碼時間比 JSON 快得多,因為 ProtoBuf 的編碼是二進制的,不需要進行編碼轉換以及無需進行冗余類型的轉換。相對而言,JSON 的編碼時間較慢。
解碼時間:相比編碼,ProtoBuf 的解碼效率要稍微低一些。但是,由于 ProtoBuf 的優勢在數據量大、結構復雜的情況下更為明顯,對于小型數據解碼時,兩者的效率差異可能不太明顯。
所以使用ProtoBuf格式代替JSON格式基本可以解掉一大半延遲問題,也是接下來IM優化的一個方向。
體驗不是一蹴而就的,不要想著一下子就做到位,一個優秀的用戶體驗和交互設計需要始終與用戶需求和反饋相結合,并不斷改進和完善。在實際設計和開發過程中,需要進行不斷的測試和優化,以確保系統的質量和可接受性。同時,需要與用戶進行積極的溝通和反饋,以便更好地理解用戶需求和意見,這一點我們之前是做的不夠好的,尤其是新版本的推廣,系統的易用性并未達到客服的期望,也是我們后期需要持續改進的一個方面。
體驗是以絕大數用戶需求為核心的,不能僅僅為了一小部分用戶而去犧牲其他用戶的使用體驗,尤其不能因為某一個用戶的反饋意見而做出過多的改變或者犧牲其他用戶的利益。體驗優化過程的不妥協也是非常重要的策略,在體驗優化過程中,必須保持理性和客觀,根據用戶調研和數據分析進行合理的權衡和決策,以實現最佳的用戶體驗。
一些小細節的優化也可以起到事半功倍的效果,在IM系統中,一些細節的優化包括:及時的消息提示、清晰的消息展示、精確的消息發送時間等等。這些小細節的優化可以直接提高客服的使用效率和體驗,從而提高客服滿意度。IM的體驗優化我們會一直做下去,有志者事竟成。
上述幾個方面我們會優先去做重要且緊急的技術改造,并不會一味的創新、優化,還是會以業務為主,緊緊圍繞業務和坐席體驗展開。
客服發送一條消息在IM應用中看似簡單,背后需要考慮的技術細節點是很多的。首先,這需要考慮到消息的發送機制和可靠性。即使是一條簡單的消息,也需要經過一系列的加密、編碼、傳輸、安全合規等等處理才能被成功接收。
最重要的是要考慮到數據實時性的問題,各種極限場景下的操作,客服發送的消息需要被及時展示到聊天頁并傳輸給用戶,客服同學在一對多的場景下工作,需要確保各會話消息不會出現不一致(丟失、重復),還有消息攔截和異常情況等問題。
因此,客服發送一條消息不僅需要技術能力和數據處理能力,還需要思考坐席體驗和數據實時性等方面的問題。開發過程中需要細致入微地處理各種問題并持續優化,從而為客服提供一個穩定、流暢、安全、友好的IM應用。
得物客服IM消息通信SDK自研之路
本文鏈接:http://www.tebozhan.com/showinfo-26-13642-0.html客服發送一條消息背后的技術和思考
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 從0手寫一個多線程日志包
下一篇: 四個流行的Java開源規則引擎和入門