轉(zhuǎn)轉(zhuǎn)客服IM系統(tǒng)的WebSocket集群架構(gòu)設(shè)計(jì)和部署方案

本文由轉(zhuǎn)轉(zhuǎn)技術(shù)李帥分享,原題“轉(zhuǎn)轉(zhuǎn)客服IM的WebSocket集群部署方案”,下文有修訂和重新排版。

1、引言

轉(zhuǎn)轉(zhuǎn)作為國內(nèi)頭部的二手閑置交易平臺,擁有上億的用戶。用戶在使用轉(zhuǎn)轉(zhuǎn)app遇到問題時,一般可以通過在線客服、熱線電話等方式聯(lián)系轉(zhuǎn)轉(zhuǎn)客服并解決問題。

客服IM系統(tǒng)是轉(zhuǎn)轉(zhuǎn)自研的在線客服系統(tǒng),是用戶和轉(zhuǎn)轉(zhuǎn)客服溝通的重要工具,主要包括機(jī)器人客服、人工客服、會話分配、技能組管理等功能。在這套系統(tǒng)中,我們使用了很多開源框架和中間件,今天講一下客服IM系統(tǒng)中WebSocket集群的的實(shí)踐和應(yīng)用。

2、快速認(rèn)識WebSocket

2.1 WebSocket 誕生背景

早期,很多網(wǎng)站為了實(shí)現(xiàn)推送技術(shù),所用的技術(shù)都是輪詢(也叫短輪詢)。輪詢是指由瀏覽器每隔一段時間向服務(wù)器發(fā)出 HTTP 請求,然后服務(wù)器返回最新的數(shù)據(jù)給客戶端。

常見的輪詢方式分為輪詢與長輪詢,它們的區(qū)別如下圖所示:

為了更加直觀感受輪詢與長輪詢之間的區(qū)別,我們來看一下具體的代碼:

這種傳統(tǒng)的模式帶來很明顯的缺點(diǎn),即瀏覽器需要不斷的向服務(wù)器發(fā)出請求,然而 HTTP 請求與響應(yīng)可能會包含較長的頭部,其中真正有效的數(shù)據(jù)可能只是很小的一部分,所以這樣會消耗很多帶寬資源。

PS:關(guān)于短輪詢、長輪詢技術(shù)的前世今身,可以詳細(xì)讀這兩篇:《新手入門貼:史上最全Web端即時通訊技術(shù)原理詳解》、《Web端即時通訊技術(shù)盤點(diǎn):短輪詢、Comet、Websocket、SSE》。

比較新的輪詢技術(shù)是?Comet。這種技術(shù)雖然可以實(shí)現(xiàn)雙向通信,但仍然需要反復(fù)發(fā)出請求。而且在?Comet?中普遍采用的 HTTP 長連接也會消耗服務(wù)器資源。

在這種情況下,HTML5 定義了 WebSocket 協(xié)議,能更好的節(jié)省服務(wù)器資源和帶寬,并且能夠更實(shí)時地進(jìn)行通訊。

Websocket 使用 ws 或 wss 的統(tǒng)一資源標(biāo)志符(URI),其中 wss 表示使用了 TLS 的 Websocket。

如:

ws://echo.websocket.org

wss://echo.websocket.org

WebSocket 與 HTTP 和 HTTPS 使用相同的 TCP 端口,可以繞過大多數(shù)防火墻的限制。

默認(rèn)情況下:

1)WebSocket 協(xié)議使用 80 端口;

2)若運(yùn)行在 TLS 之上時,默認(rèn)使用 443 端口。

2.2 WebSocket 簡介

WebSocket 是一種網(wǎng)絡(luò)傳輸協(xié)議,可在單個 TCP 連接上進(jìn)行全雙工通信,位于 OSI 模型的應(yīng)用層。WebSocket 協(xié)議在 2011 年由 IETF 標(biāo)準(zhǔn)化為?RFC 6455,后由?RFC 7936?補(bǔ)充規(guī)范。

WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。

介紹完輪詢和 WebSocket 的相關(guān)內(nèi)容之后,接下來用一張圖看一下 XHR Polling(短輪詢) 與 WebSocket 之間的區(qū)別。

XHR Polling與 WebSocket 之間的區(qū)別如下圖所示:

2.3 WebSocket 優(yōu)點(diǎn)

普遍認(rèn)為,WebSocket的優(yōu)點(diǎn)有如下幾點(diǎn):

1)較少的控制開銷:在連接創(chuàng)建后,服務(wù)器和客戶端之間交換數(shù)據(jù)時,用于協(xié)議控制的數(shù)據(jù)包頭部相對較??;

2)更強(qiáng)的實(shí)時性:由于協(xié)議是全雙工的,所以服務(wù)器可以隨時主動給客戶端下發(fā)數(shù)據(jù)。相對于 HTTP 請求需要等待客戶端發(fā)起請求服務(wù)端才能響應(yīng),延遲明顯更少;

3)保持連接狀態(tài):與 HTTP 不同的是,WebSocket 需要先創(chuàng)建連接,這就使得其成為一種有狀態(tài)的協(xié)議,之后通信時可以省略部分狀態(tài)信息;

4)更好的二進(jìn)制支持:WebSocket 定義了二進(jìn)制幀,相對 HTTP,可以更輕松地處理二進(jìn)制內(nèi)容;

5)可以支持?jǐn)U展:WebSocket 定義了擴(kuò)展,用戶可以擴(kuò)展協(xié)議、實(shí)現(xiàn)部分自定義的子協(xié)議。

由于 WebSocket 擁有上述的優(yōu)點(diǎn),所以它被廣泛地應(yīng)用在即時通訊/IM、實(shí)時音視頻、在線教育和游戲等領(lǐng)域。

對于前端開發(fā)者來說,要想使用 WebSocket 提供的強(qiáng)大能力,就必須先掌握 WebSocket API,下面帶大家一起來認(rèn)識一下 WebSocket API。

PS:如果你想要更淺顯的WebSocket入門教程,可以先讀這篇《新手快速入門:WebSocket簡明教程》后,再回來繼續(xù)學(xué)習(xí)。

3、WebSocket的易錯常識

3.1 WebSocket 與 HTTP 有什么關(guān)系?

WebSocket 是一種與 HTTP 不同的協(xié)議。兩者都位于 OSI 模型的應(yīng)用層,并且都依賴于傳輸層的 TCP 協(xié)議。

雖然它們不同,但是?RFC 6455?中規(guī)定:WebSocket 被設(shè)計(jì)為在 HTTP 80 和 443 端口上工作,并支持 HTTP 代理和中介,從而使其與 HTTP 協(xié)議兼容。 為了實(shí)現(xiàn)兼容性,WebSocket 握手使用 HTTP Upgrade 頭,從 HTTP 協(xié)議更改為 WebSocket 協(xié)議。

既然已經(jīng)提到了 OSI(Open System Interconnection Model)模型,這里分享一張很生動、很形象描述 OSI 模型的示意圖(如下圖所示)。

(圖片引用自:https://www.networkingsphere.com/2019/07/what-is-osi-model.html

當(dāng)然,WebSocket與HTTP的關(guān)系顯然不是這三兩句話可以說的清,有興趣的讀者可以詳讀下面這兩篇:

WebSocket詳解(四):刨根問底HTTP與WebSocket的關(guān)系(上篇)

WebSocket詳解(五):刨根問底HTTP與WebSocket的關(guān)系(下篇)

3.2 WebSocket 與長輪詢有什么區(qū)別?

長輪詢就是:客戶端發(fā)起一個請求,服務(wù)器收到客戶端發(fā)來的請求后,服務(wù)器端不會直接進(jìn)行響應(yīng),而是先將這個請求掛起,然后判斷請求的數(shù)據(jù)是否有更新。如果有更新,則進(jìn)行響應(yīng),如果一直沒有數(shù)據(jù),則等待一定的時間后才返回。

長輪詢的本質(zhì)還是基于 HTTP 協(xié)議,它仍然是一個一問一答(請求 — 響應(yīng))的模式。而 WebSocket 在握手成功后,就是全雙工的 TCP 通道,數(shù)據(jù)可以主動從服務(wù)端發(fā)送到客戶端。

要理解WebSocket 與長輪詢的區(qū)別,需要深刻理解長輪詢的技術(shù)原理,以下3篇中有關(guān)長輪詢的技術(shù)介紹建議深入閱讀:

Comet技術(shù)詳解:基于HTTP長連接的Web端實(shí)時通信技術(shù)

新手入門貼:史上最全Web端即時通訊技術(shù)原理詳解

Web端即時通訊技術(shù)盤點(diǎn):短輪詢、Comet、Websocket、SSE

網(wǎng)頁端IM通信技術(shù)快速入門:短輪詢、長輪詢、SSE、WebSocket

3.3 什么是 WebSocket 心跳?

網(wǎng)絡(luò)中的接收和發(fā)送數(shù)據(jù)都是使用 Socket 進(jìn)行實(shí)現(xiàn)。但是如果此套接字已經(jīng)斷開,那發(fā)送數(shù)據(jù)和接收數(shù)據(jù)的時候就一定會有問題。

可是如何判斷這個套接字是否還可以使用呢?這個就需要在系統(tǒng)中創(chuàng)建心跳機(jī)制。

所謂 “心跳” 就是定時發(fā)送一個自定義的結(jié)構(gòu)體(心跳包或心跳幀),讓對方知道自己 “在線”,以確保鏈接的有效性。

而所謂的心跳包就是客戶端定時發(fā)送簡單的信息給服務(wù)器端告訴它我還在而已。代碼就是每隔幾分鐘發(fā)送一個固定信息給服務(wù)端,服務(wù)端收到后回復(fù)一個固定信息,如果服務(wù)端幾分鐘內(nèi)沒有收到客戶端信息則視客戶端斷開。

在 WebSocket 協(xié)議中定義了 心跳 Ping 和 心跳 Pong 的控制幀:

1)心跳 Ping 幀包含的操作碼是 0x9:如果收到了一個心跳 Ping 幀,那么終端必須發(fā)送一個心跳 Pong 幀作為回應(yīng),除非已經(jīng)收到了一個關(guān)閉幀。否則終端應(yīng)該盡快回復(fù) Pong 幀;

2)心跳 Pong 幀包含的操作碼是 0xA:作為回應(yīng)發(fā)送的 Pong 幀必須完整攜帶 Ping 幀中傳遞過來的 “應(yīng)用數(shù)據(jù)” 字段。

針對第2)點(diǎn):如果終端收到一個 Ping 幀但是沒有發(fā)送 Pong 幀來回應(yīng)之前的 Ping 幀,那么終端可以選擇僅為最近處理的 Ping 幀發(fā)送 Pong 幀。此外,可以自動發(fā)送一個 Pong 幀,這用作單向心跳。

PS:這里有篇WebSocket心跳方面的IM實(shí)戰(zhàn)總結(jié)文章,有興趣可以閱讀《Web端即時通訊實(shí)踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?》。

3.4 Socket 是什么?

網(wǎng)絡(luò)上的兩個程序通過一個雙向的通信連接實(shí)現(xiàn)數(shù)據(jù)的交換,這個連接的一端稱為一個 Socket(套接字),因此建立網(wǎng)絡(luò)通信連接至少要一對端口號。

Socket 本質(zhì):是對 TCP/IP 協(xié)議棧的封裝,它提供了一個針對 TCP 或者 UDP 編程的接口,并不是另一種協(xié)議。通過 Socket,你可以使用 TCP/IP 協(xié)議。

百度百科上關(guān)于Socket的描述是這樣:

Socket 的英文原義是“孔”或“插座”:作為 BSD UNIX 的進(jìn)程通信機(jī)制,取后一種意思。通常也稱作”套接字“,用于描述IP地址和端口,是一個通信鏈的句柄,可以用來實(shí)現(xiàn)不同虛擬機(jī)或不同計(jì)算機(jī)之間的通信。

在Internet 上的主機(jī)一般運(yùn)行了多個服務(wù)軟件,同時提供幾種服務(wù)。每種服務(wù)都打開一個Socket,并綁定到一個端口上,不同的端口對應(yīng)于不同的服務(wù)。Socket 正如其英文原義那樣,像一個多孔插座。一臺主機(jī)猶如布滿各種插座的房間,每個插座有一個編號,有的插座提供 220 伏交流電, 有的提供 110 伏交流電,有的則提供有線電視節(jié)目。 客戶軟件將插頭插到不同編號的插座,就可以得到不同的服務(wù)。

關(guān)于 Socket,可以總結(jié)以下幾點(diǎn):

1)它可以實(shí)現(xiàn)底層通信,幾乎所有的應(yīng)用層都是通過 socket 進(jìn)行通信的;

2)對 TCP/IP 協(xié)議進(jìn)行封裝,便于應(yīng)用層協(xié)議調(diào)用,屬于二者之間的中間抽象層;

3)TCP/IP 協(xié)議族中,傳輸層存在兩種通用協(xié)議: TCP、UDP,兩種協(xié)議不同,因?yàn)椴煌瑓?shù)的 socket 實(shí)現(xiàn)過程也不一樣。

下圖說明了面向連接的協(xié)議的套接字 API 的客戶端/服務(wù)器關(guān)系:

PS:要說WebSocket和Socket的關(guān)系,這篇《WebSocket詳解(六):刨根問底WebSocket與Socket的關(guān)系》有專門進(jìn)行詳細(xì)分享,建議閱讀。

4、選擇WebSocket協(xié)議

IM是實(shí)時通信(Instant Messaging)的簡稱,實(shí)時是IM系統(tǒng)的基本要求(詳見《什么是IM系統(tǒng)的實(shí)時性?》)。在客服系統(tǒng)中,用戶和客服實(shí)時收發(fā)消息,是最基礎(chǔ)、最重要的功能。

WebSocket(以下簡稱ws)是一種在單個TCP連接上進(jìn)行全雙工通信的協(xié)議,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。能夠以較小的開銷,實(shí)現(xiàn)更強(qiáng)的實(shí)時性。因此客服IM系統(tǒng)采用了ws協(xié)議,實(shí)現(xiàn)了服務(wù)端同時接收與發(fā)送數(shù)據(jù)的能力。

5、WebSocket服務(wù)的集群式部署

在實(shí)際生產(chǎn)環(huán)境中,我們不可能使用單臺服務(wù)器做ws服務(wù),一旦出現(xiàn)問題就是毀滅性的,所以我們會使用集群式部署ws服務(wù)。

ws協(xié)議是全雙工通信協(xié)議,可以雙向通信的,部署多臺機(jī)器后,如下圖所示,不同用戶會分別和不同的機(jī)器連接,A如何向C發(fā)送消息呢?

具體是:

1)我們在nginx配置中,將ws服務(wù)的負(fù)載均衡策略設(shè)置為ip_hash,保證用戶在IP不變的情況,一直分配在一個固定服務(wù)器上;

2)用戶與ws服務(wù)建立連接后,獲取當(dāng)前機(jī)器hostname,將用戶uid與機(jī)器hostname關(guān)系存儲在redis中;

3)每個ws服務(wù)都維護(hù)了一個獨(dú)立的consumer,采用廣播消費(fèi)模式,僅消費(fèi)屬于自己tag的消息,tag即為當(dāng)前機(jī)器hostname。

6、IM消息在集群架構(gòu)下發(fā)送流程

IM消息在當(dāng)前集群架構(gòu)下的發(fā)送流程是這樣的。

1)用戶A在向用戶C發(fā)送消息時,用戶A將消息發(fā)送給ws-1服務(wù)器,ws-1服務(wù)接收消息后,從redis中獲取用戶C的連接信息。

2)ws-1服務(wù)器拿到用戶C和ws-2的關(guān)系后,設(shè)置mq消息tag="ws-2",直接將用戶消息通過mq發(fā)送出去。

3)ws-2服務(wù)器的consumer接收到對應(yīng)mq消息后,即可通過ws連接將消息推送用戶C 至此,我們就完成了一條消息的發(fā)送與接收。

關(guān)于集群架構(gòu)下IM實(shí)例間的消息可靠投遞,也可以詳細(xì)參考下面的資料:

閑魚億級IM消息系統(tǒng)的可靠投遞優(yōu)化實(shí)踐

融云技術(shù)分享:全面揭秘億級IM消息的可靠投遞機(jī)制

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

一套億級用戶的IM架構(gòu)技術(shù)干貨(下篇):可靠性、有序性、弱網(wǎng)優(yōu)化等

7、集群架構(gòu)下的斷線重連邏輯

網(wǎng)絡(luò)環(huán)境錯綜復(fù)雜,難免會有網(wǎng)絡(luò)掉線、網(wǎng)絡(luò)環(huán)境切換的情況,都會導(dǎo)致用戶和ws服務(wù)的連接發(fā)生變化。

一個比較典型的場景就是C端用戶網(wǎng)絡(luò)在4G和wifi之間進(jìn)行切換,會導(dǎo)致ip變化,從而可能到導(dǎo)致用戶和另外的ws服務(wù)再次建立連接。這種情況可能會導(dǎo)致消息重復(fù)發(fā)送、以及額外的資源消耗,所以要盡量避免。

處理方式如下:

1)即時清理:用戶與ws服務(wù)建立連接時,當(dāng)前ws服務(wù)查詢r(jià)edis中存儲的用戶連接信息。當(dāng)連接信息與當(dāng)前ws服務(wù)不一致時,當(dāng)前ws服務(wù)更新redis存儲信息、并發(fā)出廣播mq消息,通知其他ws服務(wù)關(guān)閉與當(dāng)前用戶的連接通道。

2)定時清理:除此之外,還需要前端同學(xué)配合,定時向連接的ws服務(wù)發(fā)送心跳消息,ws服務(wù)定時檢測用戶連接的心跳情況,關(guān)閉廢棄的用戶連接。

關(guān)于WebSocket的斷線快速重連,這里還有篇文章可一并閱讀:《Web端即時通訊實(shí)踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?》。

8、本文小結(jié)

以上就是我們在客服IM系統(tǒng)中使用WebSocket協(xié)議實(shí)現(xiàn)的消息收發(fā)的主要流程。要實(shí)現(xiàn)一個完整的IM系統(tǒng),不僅要保證消息的實(shí)時性,消息的一致性、順序性也很重要,還有網(wǎng)絡(luò)異常等情況下的重連、用戶心跳檢測等,這些功能需要客戶端同學(xué)一起協(xié)作才能完成。

9、參考資料

[1]?網(wǎng)頁端IM通信技術(shù)快速入門:短輪詢、長輪詢、SSE、WebSocket

[2]?搞懂現(xiàn)代Web端即時通訊技術(shù)一文就夠:WebSocket、socket.io、SSE

[3]?萬字長文,一篇吃透WebSocket:概念、原理、易錯常識、動手實(shí)踐

[4]?WebSocket從入門到精通,半小時就夠!

[5]?Web端即時通訊實(shí)踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?

[6]?為何基于TCP協(xié)議的移動端IM仍然需要心跳?;顧C(jī)制?

[7]?一文讀懂即時通訊應(yīng)用中的網(wǎng)絡(luò)心跳包機(jī)制:作用、原理、實(shí)現(xiàn)思路等

[8]?阿里IM技術(shù)分享(五):閑魚億級IM消息系統(tǒng)的及時性優(yōu)化實(shí)踐

[9]?萬字長文:手把手教你實(shí)現(xiàn)一套高效的IM長連接自適應(yīng)心跳保活機(jī)制

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

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

[12]?轉(zhuǎn)轉(zhuǎn)平臺IM系統(tǒng)架構(gòu)設(shè)計(jì)與實(shí)踐(一):整體架構(gòu)設(shè)計(jì)

[13]?轉(zhuǎn)轉(zhuǎn)平臺IM系統(tǒng)架構(gòu)設(shè)計(jì)與實(shí)踐(二):詳細(xì)設(shè)計(jì)與實(shí)現(xiàn)

[14]?支持百萬人超大群聊的Web端IM架構(gòu)設(shè)計(jì)與實(shí)踐

[15]?一套分布式IM即時通訊系統(tǒng)的技術(shù)選型和架構(gòu)設(shè)計(jì)

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

[17]?得物從0到1自研客服IM系統(tǒng)的技術(shù)實(shí)踐之路

[18]?閑魚億級IM消息系統(tǒng)的可靠投遞優(yōu)化實(shí)踐

[19]?融云技術(shù)分享:全面揭秘億級IM消息的可靠投遞機(jī)制

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

[21]?一套億級用戶的IM架構(gòu)技術(shù)干貨(下篇):可靠性、有序性、弱網(wǎng)優(yōu)化等

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

[23]?什么是IM系統(tǒng)的實(shí)時性?

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容