目錄
100W級(jí)連接,愛奇藝WebSocket推送網(wǎng)關(guān)架構(gòu)
1、舊方案存在的技術(shù)痛點(diǎn)
2、新方案的技術(shù)目標(biāo)
3、新方案的技術(shù)選型
4、新方案的實(shí)現(xiàn)思路
4.1 系統(tǒng)架構(gòu)
4.2 會(huì)話管理
4.3 監(jiān)控與報(bào)警
5、新方案的性能壓測(cè)
6、新方案的實(shí)際應(yīng)用案例
7、總結(jié)
100W級(jí)連接,愛奇藝WebSocket推送網(wǎng)關(guān)架構(gòu)
HTTP 協(xié)議屬于一種無狀態(tài)、基于 TCP 的請(qǐng)求/響應(yīng)模式的協(xié)議,
HTTP 協(xié)議中,只有客戶端能發(fā)起請(qǐng)求,由服務(wù)端進(jìn)行回應(yīng)。
雖然,在許多情況下,這種請(qǐng)求/響應(yīng)的拉取模式能夠滿足需求。
然而,在特定情況下,例如實(shí)時(shí)通知(如 IM 中的離線消息推送最為典型)和消息推送等應(yīng)用場(chǎng)景,需要將數(shù)據(jù)實(shí)時(shí)推到客戶端,這就要求服務(wù)端具備主動(dòng)推送數(shù)據(jù)的能力。
如何推呢?
傳統(tǒng)的 Web 服務(wù)端推送技術(shù),包括短輪詢、長(zhǎng)輪詢等,雖然能在一定程度上解決問題,但也存在如時(shí)效性、資源浪費(fèi)等問題。
HTML5 標(biāo)準(zhǔn)推出的?WebSocket 規(guī)范基本改變了這種狀況,已經(jīng)成為當(dāng)前服務(wù)端消息推送技術(shù)的主流。
本文將分享愛奇藝在基于 Netty 實(shí)現(xiàn) WebSocket 長(zhǎng)連接實(shí)時(shí)推送網(wǎng)關(guān)過程中的實(shí)踐經(jīng)驗(yàn)和總結(jié)。
1、舊方案存在的技術(shù)痛點(diǎn)
愛奇藝號(hào)作為我們內(nèi)容生態(tài)的關(guān)鍵部分,作為前端系統(tǒng),對(duì)用戶體驗(yàn)有著較高的要求,這直接影響著創(chuàng)作者的創(chuàng)作熱情。
當(dāng)前,愛奇藝號(hào)在多個(gè)業(yè)務(wù)場(chǎng)景中應(yīng)用了 WebSocket 實(shí)時(shí)推送技術(shù),包括:
1)用戶評(píng)論:實(shí)時(shí)地將評(píng)論消息推送至瀏覽器;
2)實(shí)名認(rèn)證:在合同簽署前,需要對(duì)用戶進(jìn)行實(shí)名認(rèn)證,用戶掃描二維碼后進(jìn)入第三方的認(rèn)證頁(yè)面,認(rèn)證完成后異步通知瀏覽器認(rèn)證狀態(tài);
3)活體識(shí)別:類似于實(shí)名認(rèn)證,當(dāng)活體識(shí)別完成后,異步將結(jié)果通知瀏覽器。
在實(shí)際業(yè)務(wù)開發(fā)中,我們發(fā)現(xiàn) WebSocket 實(shí)時(shí)推送技術(shù)在使用過程中存在一些問題。
這些問題是:
1)首先:WebSocket 技術(shù)棧不統(tǒng)一,既有基于 Netty 實(shí)現(xiàn)的,也有基于 Web 容器實(shí)現(xiàn)的,給開發(fā)和維護(hù)帶來困難;
2)其次:WebSocket 實(shí)現(xiàn)分散在各個(gè)工程中,與業(yè)務(wù)系統(tǒng)緊密耦合,如果有其他業(yè)務(wù)需要集成 WebSocket,將面臨重復(fù)開發(fā)的困境,浪費(fèi)成本、效率低下;
3)第三:WebSocket 是有狀態(tài)協(xié)議,客戶端連接服務(wù)器時(shí)只與集群中一個(gè)節(jié)點(diǎn)連接,數(shù)據(jù)傳輸過程中也只與這一節(jié)點(diǎn)通信。WebSocket 集群需要解決會(huì)話共享的問題。如果只采用單節(jié)點(diǎn)部署,雖然可以避免這一問題,但無法水平擴(kuò)展以支持更高的負(fù)載,存在單點(diǎn)故障風(fēng)險(xiǎn);
4)最后:最后:缺乏監(jiān)控與報(bào)警,雖然可以通過 Linux 的 Socket 連接數(shù)大致評(píng)估 WebSocket 長(zhǎng)連接數(shù),但數(shù)字并不準(zhǔn)確,也無法得知用戶數(shù)等具有業(yè)務(wù)含義的指標(biāo)數(shù)據(jù);無法與現(xiàn)有的微服務(wù)監(jiān)控整合,實(shí)現(xiàn)統(tǒng)一監(jiān)控和報(bào)警。
2、新方案的技術(shù)目標(biāo)
如上所述,為了解決舊方案中存在的問題,我們需要實(shí)現(xiàn)統(tǒng)一的 WebSocket 長(zhǎng)連接實(shí)時(shí)推送網(wǎng)關(guān)。
這套新的網(wǎng)關(guān)需要具備以下特點(diǎn):
1)集中實(shí)現(xiàn)長(zhǎng)連接管理和推送能力:采用統(tǒng)一的技術(shù)棧,將長(zhǎng)連接作為基礎(chǔ)功能進(jìn)行沉淀,以便于功能的迭代和維護(hù);
2)與業(yè)務(wù)解耦:將業(yè)務(wù)邏輯與長(zhǎng)連接通信分離,使得業(yè)務(wù)系統(tǒng)無需關(guān)心通信細(xì)節(jié),避免了重復(fù)開發(fā),節(jié)約了研發(fā)成本;
3)使用簡(jiǎn)單:提供 HTTP 推送通道,便于各種開發(fā)語言的接入。業(yè)務(wù)系統(tǒng)只需進(jìn)行簡(jiǎn)單的調(diào)用,便可實(shí)現(xiàn)數(shù)據(jù)推送,從而提高研發(fā)效率;
4)分布式架構(gòu):構(gòu)建多節(jié)點(diǎn)的集群,支持水平擴(kuò)展以應(yīng)對(duì)業(yè)務(wù)增長(zhǎng)帶來的挑戰(zhàn);節(jié)點(diǎn)故障不會(huì)影響服務(wù)的整體可用性,確保高可靠性;
5)多端消息同步:允許用戶使用多個(gè)瀏覽器或標(biāo)簽頁(yè)同時(shí)登錄在線,確保消息同步發(fā)送;
6)多維度監(jiān)控與報(bào)警:將自定義監(jiān)控指標(biāo)與現(xiàn)有的微服務(wù)監(jiān)控系統(tǒng)連接,當(dāng)出現(xiàn)問題時(shí)可以及時(shí)報(bào)警,保證服務(wù)的穩(wěn)定性。
3、新方案的技術(shù)選型
在眾多的 WebSocket 實(shí)現(xiàn)中,經(jīng)過對(duì)性能、擴(kuò)展性、社區(qū)支持等各方面的權(quán)衡,我們最終確定了 Netty。
Netty 是一個(gè)高性能、事件驅(qū)動(dòng)、異步非阻塞的網(wǎng)絡(luò)通信框架,已在許多知名的開源項(xiàng)目中得到廣泛應(yīng)用。
WebSocket 具有狀態(tài)特性,這與 HTTP 的無狀態(tài)特性不同,因此無法像 HTTP 一樣通過集群方式實(shí)現(xiàn)負(fù)載均衡。在長(zhǎng)連接建立后,它會(huì)與服務(wù)端的某個(gè)節(jié)點(diǎn)保持會(huì)話,所以在集群環(huán)境下,要確定會(huì)話屬于哪個(gè)節(jié)點(diǎn)會(huì)有些困難。
解決以上問題一般有兩種技術(shù)方案:
1)一種是使用類似于微服務(wù)注冊(cè)中心的技術(shù)來維護(hù)全局的會(huì)話映射關(guān)系;
2)另一種是使用事件廣播,由各節(jié)點(diǎn)自行判斷是否持有會(huì)話。這兩種方案的對(duì)比如下表所示。
WebSocket集群方案:
方案 | 優(yōu)點(diǎn) | 缺點(diǎn) |
---|---|---|
注冊(cè)中心 | 會(huì)話映射關(guān)系清晰,集群規(guī)模較大時(shí)更合適 | 實(shí)現(xiàn)復(fù)雜,強(qiáng)依賴注冊(cè)中心,有額外運(yùn)維成本 |
事件廣播 | 實(shí)現(xiàn)簡(jiǎn)單更加輕量 | 節(jié)點(diǎn)較多時(shí),所有節(jié)點(diǎn)均被廣播,資源浪費(fèi) |
考慮到實(shí)現(xiàn)成本和集群規(guī)模,我們選擇了輕量級(jí)的事件廣播方案。
實(shí)現(xiàn)廣播的方法有多種,如基于 RocketMQ 的消息廣播、基于 Redis 的 Publish/Subscribe、基于 ZooKeeper 的通知等。
這些方案的優(yōu)缺點(diǎn)對(duì)比如下表所示。在考慮到吞吐量、實(shí)時(shí)性、持久化和實(shí)現(xiàn)難易程度等因素后,我們最終選擇了 RocketMQ。
廣播的實(shí)現(xiàn)方案對(duì)比:
方案 | 優(yōu)點(diǎn) | 缺點(diǎn) |
---|---|---|
基于RocketMQ | 吞吐量高、高可用、保證可靠 | 實(shí)時(shí)性不如Redis |
基于Redis | 實(shí)時(shí)性高、實(shí)現(xiàn)簡(jiǎn)單 | 不保證可靠 |
基于ZooKeeper | 實(shí)現(xiàn)簡(jiǎn)單 | 寫入性能較差,不適合頻繁寫入場(chǎng)景 |
4、新方案的實(shí)現(xiàn)思路
4.1 系統(tǒng)架構(gòu)
網(wǎng)關(guān)的整體架構(gòu)如下圖所示:
網(wǎng)關(guān)的整體流程如下:
1)客戶端與網(wǎng)關(guān)的任何一個(gè)節(jié)點(diǎn)建立長(zhǎng)連接,節(jié)點(diǎn)會(huì)將其加入到內(nèi)存中的長(zhǎng)連接隊(duì)列??蛻舳藭?huì)定期向服務(wù)端發(fā)送心跳消息,若超過設(shè)定時(shí)間還未收到心跳,則認(rèn)為客戶端與服務(wù)端的長(zhǎng)連接已斷開,服務(wù)端會(huì)關(guān)閉連接,清理內(nèi)存中的會(huì)話。
2)當(dāng)業(yè)務(wù)系統(tǒng)需要向客戶端推送數(shù)據(jù)時(shí),通過網(wǎng)關(guān)提供的HTTP接口將數(shù)據(jù)發(fā)送至網(wǎng)關(guān)。
3)在收到推送請(qǐng)求后,網(wǎng)關(guān)會(huì)將消息寫入RocketMQ。
4)網(wǎng)關(guān)作為消費(fèi)者,以廣播模式消費(fèi)消息,所有節(jié)點(diǎn)都能收到消息。
5)節(jié)點(diǎn)在收到消息后會(huì)判斷推送的消息目標(biāo)是否在其內(nèi)存中維護(hù)的長(zhǎng)連接隊(duì)列里,如果存在則通過長(zhǎng)連接推送數(shù)據(jù),否則直接忽略。
網(wǎng)關(guān)通過多節(jié)點(diǎn)構(gòu)成集群,每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分長(zhǎng)連接,實(shí)現(xiàn)負(fù)載均衡。當(dāng)面臨大量連接時(shí),也可以通過增加節(jié)點(diǎn)來分散壓力,實(shí)現(xiàn)水平擴(kuò)展。
同時(shí),當(dāng)節(jié)點(diǎn)出現(xiàn)故障時(shí),客戶端會(huì)嘗試與其他節(jié)點(diǎn)重新建立長(zhǎng)連接,確保服務(wù)的整體可用性。
4.2 會(huì)話管理
在 WebSocket 長(zhǎng)連接建立后,會(huì)話信息會(huì)保存在各個(gè)節(jié)點(diǎn)的內(nèi)存中。
SessionManager 組件負(fù)責(zé)管理會(huì)話,它內(nèi)部使用哈希表來維護(hù) UID 與 UserSession 的關(guān)聯(lián)。
UserSession 表示用戶層面的會(huì)話,一個(gè)用戶可能同時(shí)擁有多個(gè)長(zhǎng)連接,因此 UserSession 內(nèi)部同樣使用哈希表來維護(hù) Channel 與 ChannelSession 的關(guān)聯(lián)。
為了防止用戶無休止地創(chuàng)建長(zhǎng)連接,當(dāng) UserSession 內(nèi)部的 ChannelSession 超過一定數(shù)量時(shí),它會(huì)關(guān)閉最早建立的 ChannelSession,以減少服務(wù)器資源的占用。
SessionManager、UserSession、ChannelSession 的關(guān)系如下圖所示。
SessionManager組件:
4.3 監(jiān)控與報(bào)警
為了掌握集群中建立的長(zhǎng)連接數(shù)量和包含的用戶數(shù)量,網(wǎng)關(guān)提供了基本的監(jiān)控和報(bào)警功能。
網(wǎng)關(guān)接入了?Micrometer?(https://www.oschina.net/p/micrometer?hmsr=aladdin1e1),將連接數(shù)和用戶數(shù)作為自定義指標(biāo)暴露,供?Prometheus?(https://prometheus.io/)進(jìn)行采集,從而實(shí)現(xiàn)了與現(xiàn)有的微服務(wù)監(jiān)控系統(tǒng)打通。
在Grafana?(https://grafana.com/)中,可以方便地查看連接數(shù)、用戶數(shù)、JVM、CPU、內(nèi)存等指標(biāo)數(shù)據(jù),了解網(wǎng)關(guān)當(dāng)前的服務(wù)能力和壓力。報(bào)警規(guī)則也可以在 Grafana 中配置,當(dāng)數(shù)據(jù)異常時(shí)觸發(fā)奇信(內(nèi)部報(bào)警平臺(tái))報(bào)警。
5、新方案的性能壓測(cè)
壓測(cè)準(zhǔn)備:
-
1)選擇兩臺(tái)配置為 4 核 16G 的虛擬機(jī),分別作為服務(wù)器和客戶端;
-
2)在壓力測(cè)試時(shí),為網(wǎng)關(guān)開放 20 個(gè)端口,同時(shí)啟動(dòng) 20 個(gè)客戶端;
-
3)每個(gè)客戶端使用一個(gè)服務(wù)器端口建立 5 萬個(gè)連接,從而可以同時(shí)創(chuàng)建百萬個(gè)連接。
連接數(shù)(百萬級(jí))與內(nèi)存使用情況如下圖所示:
[root@sy-dev-1de4f0c2a?target]#?ss?-s?;?free?-h
Total:?1002168?(kernel?1002250)
TCP:?1002047?(estab?1002015,?closed?4,?orphaned?0,?synrecv?0,?timewait?4/0),?ports?0
Transport?Total???IP??????IPv6
*?????????1002250?-???????-
RAW???????0???????0???????0
UDP???????4???????2???????2
TCP???????1002043?1002041?2
INET??????1002047?1002043?4
FRAG??????0???????0???????0
??????????total???used????free??shared??buff/cache??available
Mem:??????15G?????4.5G????4.5G??232K????6.5G????????8.2G
Swap:?????4.0G????14M?????4.0G
給百萬個(gè)長(zhǎng)連接同時(shí)發(fā)送一條消息,采用單線程發(fā)送,服務(wù)器發(fā)送完成的平均耗時(shí)在10s左右,如下圖所示。
服務(wù)器推送耗時(shí):
2021-01-25?20:51:02.614?INFO?[mp-tcp-gateway,54d52e7e4240b65a,54d52e7e4240b65a,false]
[600ebeb62@2559f4507adee3b316c571/507adee3b316c571]?89558?---?[nio-8080-exec-6]
c.i.m.t.g.controller.NotifyController:?[]?[UID:]?send?message?...
2021-01-25?20:51:11.973?INF0?[mp-tcp-gateway,54d52e7e4240b65a,54d52e7e4240b65a,false]
[1600ebeb62@2559f4507adee3b316c571/507adee3b316c571]?89558?---?[nio-8080-exec-6]
c.i.m.t.g.controller.NotifyController:?[]?[UID:]?send?message?to?1001174?channels
一般同一用戶同時(shí)建立的長(zhǎng)連接都在個(gè)位數(shù)。
以10個(gè)長(zhǎng)連接為例,在并發(fā)數(shù)600、持續(xù)時(shí)間120s條件下壓測(cè),推送接口的TPS大約在1600+,如下圖所示。
長(zhǎng)連接10、并發(fā)600、持續(xù)時(shí)間120s的壓測(cè)數(shù)據(jù):
當(dāng)前的性能指標(biāo)已滿足我們的實(shí)際業(yè)務(wù)場(chǎng)景,可支持未來的業(yè)務(wù)增長(zhǎng)。
6、新方案的實(shí)際應(yīng)用案例
為了更形象地展示優(yōu)化效果,文章最后,我們以封面圖添加濾鏡效果為例,介紹了一個(gè)愛奇藝號(hào)采用新 WebSocket 網(wǎng)關(guān)方案的實(shí)例。
愛奇藝號(hào)自媒體在發(fā)布視頻時(shí),可以選擇為封面圖添加濾鏡效果,引導(dǎo)用戶提供更高質(zhì)量的封面。
當(dāng)用戶選擇封面圖后,會(huì)提交一個(gè)異步的后臺(tái)處理任務(wù)。
一旦異步任務(wù)完成,通過 WebSocket 將不同濾鏡效果處理后的圖片返回給瀏覽器,業(yè)務(wù)場(chǎng)景如下圖所示。
從研發(fā)效率的角度來看,如果在業(yè)務(wù)系統(tǒng)中集成 WebSocket,至少需要 1-2 天的開發(fā)時(shí)間。
而直接使用新的 WebSocket 網(wǎng)關(guān)的推送功能,只需簡(jiǎn)單的接口調(diào)用就能實(shí)現(xiàn)數(shù)據(jù)推送,將開發(fā)時(shí)間降低到分鐘級(jí)別,大幅提高研發(fā)效率。
從運(yùn)維成本的角度來看,業(yè)務(wù)系統(tǒng)不再包含與業(yè)務(wù)邏輯無關(guān)的通信細(xì)節(jié),代碼的可維護(hù)性更強(qiáng),系統(tǒng)架構(gòu)變得更簡(jiǎn)單,運(yùn)維成本大幅降低。
7、總結(jié)
WebSocket 是實(shí)現(xiàn)服務(wù)端推送的主流技術(shù),適當(dāng)使用可以有效提升系統(tǒng)響應(yīng)能力,增強(qiáng)用戶體驗(yàn)。
通過 WebSocket 長(zhǎng)連接網(wǎng)關(guān),可以迅速為系統(tǒng)增加數(shù)據(jù)推送能力,有效降低運(yùn)維成本,提高開發(fā)效率。
長(zhǎng)連接網(wǎng)關(guān)的價(jià)值在于:
-
1)它封裝了 WebSocket 通信細(xì)節(jié),與業(yè)務(wù)系統(tǒng)解耦,使得長(zhǎng)連接網(wǎng)關(guān)與業(yè)務(wù)系統(tǒng)可獨(dú)立優(yōu)化迭代,避免重復(fù)開發(fā),便于開發(fā)與維護(hù);
-
2)網(wǎng)關(guān)提供了簡(jiǎn)單易用的 HTTP 推送通道,支持多種開發(fā)語言接入,便于系統(tǒng)集成和使用;
-
3)網(wǎng)關(guān)采用了分布式架構(gòu),可以實(shí)現(xiàn)服務(wù)的水平擴(kuò)容、負(fù)載均衡與高可用;
-
4)網(wǎng)關(guān)集成了監(jiān)控與報(bào)警,當(dāng)系統(tǒng)異常時(shí)能及時(shí)預(yù)警,確保服務(wù)的健康和穩(wěn)定。
目前,新的 WebSocket 長(zhǎng)連接實(shí)時(shí)網(wǎng)關(guān)已在愛奇藝號(hào)圖片濾鏡結(jié)果通知、MCN 電子簽章等多個(gè)業(yè)務(wù)場(chǎng)景中得到應(yīng)用。文章來源:http://www.zghlxwxcb.cn/news/detail-817456.html
未來還有許多方面需要探索,例如消息的重發(fā)與 ACK、WebSocket 二進(jìn)制數(shù)據(jù)的支持、多租戶的支持等。文章來源地址http://www.zghlxwxcb.cn/news/detail-817456.html
到了這里,關(guān)于架構(gòu)設(shè)計(jì)內(nèi)容分享(四十一):100萬級(jí)連接,愛奇藝WebSocket網(wǎng)關(guān)如何架構(gòu)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!