說(shuō)一說(shuō)websocket通道的水平擴(kuò)展性

一、背景

隨著建立通道的房間和人數(shù)增加到一定規(guī)模,給我們的架構(gòu)之?dāng)U展性提出了考驗(yàn),本文主要是講述通道服務(wù)的水平擴(kuò)展性,垂直擴(kuò)展不在本文的范圍內(nèi)。

前文也有講述,我們的現(xiàn)狀是缺乏通道的接入層,連接是隨機(jī)路由到后端節(jié)點(diǎn)。換句話說(shuō),同一個(gè)房間的用戶,會(huì)分散到多個(gè)后端節(jié)點(diǎn)。這樣的話,A用戶想要發(fā)送消息給同房間的B用戶,目前是使用Mq廣播消息,讓所有的后端節(jié)點(diǎn)都消費(fèi)該消費(fèi)。

缺點(diǎn)是:很多消息廣播出去,導(dǎo)致消息的重復(fù)處理,每個(gè)節(jié)點(diǎn)都要消費(fèi)同等數(shù)量的消息。最重要的是,這不利于服務(wù)的水平擴(kuò)展。

二、目標(biāo)

  • 1、彈性擴(kuò)展
  • 2、通道的連接路由到后端節(jié)點(diǎn),有效期默認(rèn)為當(dāng)天,允許隔天重新創(chuàng)建通道
  • 3、擴(kuò)展的同時(shí)不能隨意更換房間
  • 4、擴(kuò)展的同時(shí)不能斷開已連上的通道

三、方案一--kong plugin改寫upstream

自定義kong插件,調(diào)用方額外傳入header字段,計(jì)算hash值,選擇對(duì)應(yīng)的upsteam。

image.png

既然是upstream,就意味著后端的pod節(jié)點(diǎn)可以是多個(gè),對(duì)比方案二的高可用相對(duì)更好。

主要內(nèi)容是開發(fā)自定義的kong插件,讀取websocket header頭部字段,求模計(jì)算,選擇對(duì)應(yīng)的upstream。

好處是:可以記錄下各個(gè)upstream已連接上的課堂列表,當(dāng)有新的課堂來(lái)臨,可以選擇路由到連接空閑的upstream。

四、方案二--kong upsteam 的 hash on header

要求調(diào)用方的頭部,新增上傳計(jì)算路由的字段。比如學(xué)校ID,用戶ID,課堂ID等等。

image.png

不用額外的開發(fā)工作,相對(duì)比方案一,它的路由機(jī)制沒(méi)有那么靈活,只保證同一個(gè)課堂下的連接請(qǐng)求到同一個(gè)節(jié)點(diǎn)。而無(wú)法對(duì)節(jié)點(diǎn)的負(fù)載進(jìn)行適當(dāng)?shù)木鶖偅热绻?jié)點(diǎn)1已連接了2個(gè)課堂,節(jié)點(diǎn)2還未有1個(gè)課堂,來(lái)臨的第3個(gè)課堂還有可能連接到第1個(gè)節(jié)點(diǎn)。

五、方案三--命名服務(wù)之zookeeper

單元化的需要,我們根據(jù)不同的學(xué)校ID可配置不同的通道地址。本次需求可以進(jìn)一步細(xì)化到課堂ID,在每次進(jìn)入課堂前,調(diào)用命名服務(wù),取得配置好的通道地址。

image.png

客戶端增加一次獲取通道地址的請(qǐng)求,可以在創(chuàng)建課堂的時(shí)候,就確定其應(yīng)該連接的通道地址。

但是業(yè)務(wù)服務(wù)要獲取通道地址,改動(dòng)的代碼就比較多了。最主要的是業(yè)務(wù)服務(wù)不可能每次都獲取,要求把<課堂ID,通道地址>存儲(chǔ)到Jvm內(nèi)存。

pod在創(chuàng)建的時(shí)候,注冊(cè)到zk,隨著節(jié)點(diǎn)銷毀而從zk下線。這使得通道集群保持最新。

六、方案四--命名服務(wù)之gossip

上面額外引入了zookeeper這一中間件,你可以使用分布式協(xié)議gossip,使得通道集群的信息在各個(gè)節(jié)點(diǎn)之間共享。

image.png

主要步驟如下:

  • 1、客戶端向通道服務(wù)發(fā)起http請(qǐng)求,頭部攜帶課堂ID。
  • 2、服務(wù)端任意一個(gè)節(jié)點(diǎn),根據(jù)課堂ID的hash算法,得出它應(yīng)該連接的通道地址,返回給客戶端。
  • 3、客戶端根據(jù)上一步得到的通道地址,建立ws連接。
  • 4、業(yè)務(wù)服務(wù)集群的每個(gè)jvm節(jié)點(diǎn),在啟動(dòng)的時(shí)候,任意連上一個(gè)通道地址。由該鏈路,實(shí)時(shí)推送課堂和通道的映射關(guān)系給業(yè)務(wù)服務(wù)。
  • 5、業(yè)務(wù)服務(wù)得到N個(gè)連接地址,除自身已連上的通道地址外, 以次和剩下的通道建立連接。

改動(dòng)點(diǎn):

  • 1、客戶端在建立連接前,多一次獲取通道地址的請(qǐng)求,可以是ws協(xié)議,也可以是http協(xié)議。
  • 2、業(yè)務(wù)服務(wù)如果有2個(gè)節(jié)點(diǎn),通道服務(wù)有4個(gè)節(jié)點(diǎn),那么每個(gè)節(jié)點(diǎn)會(huì)建立4個(gè)通道連接,總共會(huì)有4 * 2 = 8 個(gè)連接。
image.png

上面獲取通道地址是通過(guò)http協(xié)議,你也可以使用ws協(xié)議。流程如下:


image.png

這里,把kong網(wǎng)關(guān)變成了"SLB總?cè)肟?,它會(huì)可能二次建立連接,好處是通道服務(wù)不用額外提供http接口了。

七、問(wèn)題場(chǎng)景

1、場(chǎng)景一--ws連接數(shù)不夠

  • 解決方法:擴(kuò)展后端服務(wù)的節(jié)點(diǎn)數(shù),也即擴(kuò)容pod。

2、場(chǎng)景二--N個(gè)課堂的使用隔離性

  • 讓通道服務(wù)變成有狀態(tài)的,rabbitmq廣播消息通過(guò)vhost隔離多個(gè)后端集群。
  • 不同的課堂路由到不同的后端集群,甚至可以針對(duì)一個(gè)大課堂對(duì)應(yīng)一個(gè)后端節(jié)點(diǎn)。

3、場(chǎng)景三--保證通道列表的變更實(shí)時(shí)刷新

  • 業(yè)務(wù)服務(wù)和通道服務(wù)保持長(zhǎng)連接,由通道實(shí)時(shí)推送給業(yè)務(wù)服務(wù)。

4、場(chǎng)景四--保證路由關(guān)系的變更實(shí)時(shí)刷新

  • 通道服務(wù),在客戶端和通道服務(wù)建立連接前,我們根據(jù)客戶端上報(bào)上來(lái)的頭部字段,計(jì)算出應(yīng)該路由到哪個(gè)通道。
  • 第二步,找到業(yè)務(wù)服務(wù)和自己連接上的通道,實(shí)時(shí)推送給業(yè)務(wù)服務(wù)。由后者進(jìn)行刷新內(nèi)存,供選擇通道。

八、總結(jié)

數(shù)據(jù)存儲(chǔ)

  • 課堂對(duì)應(yīng)的通道地址的映射關(guān)系(每次都會(huì)根據(jù)課堂ID,計(jì)算出它應(yīng)該對(duì)應(yīng)哪個(gè)通道)
  • 通道列表的刷新(涉及到通道服務(wù)的彈性擴(kuò)縮容)

消息發(fā)送的兩種方式

  • 1、客戶端和通道服務(wù)建立連接
  • 2、客戶端調(diào)用業(yè)務(wù)服務(wù)的接口,由業(yè)務(wù)服務(wù)告知通道服務(wù)。(這里的業(yè)務(wù)服務(wù)充當(dāng)中轉(zhuǎn)的角色)
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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