日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

前導(dǎo)

近期有個同事跟我說遇到一件很奇怪的事情,時不時收到售后反饋說 部分用戶無法接收到聊天室(WebSocket 服務(wù))消息,然而在測試服以各種方式測試都無法復(fù)現(xiàn)這種現(xiàn)象。于是陷入沉思,因為這個問題必須解決,用戶必須要退出聊天室再重新進(jìn)去才能看到這些丟失的消息,已經(jīng)嚴(yán)重影響到業(yè)務(wù)間客服與用戶的正常溝通。

這到底是什么原因呢?而且沒法在測服復(fù)現(xiàn)。

這個架構(gòu)服務(wù)采用的是 php Swoole , 用戶與客戶端FD 的關(guān)系綁定是通過 Swoole Table (服務(wù)進(jìn)程間內(nèi)存共享) 實現(xiàn), 同事反映說在各個環(huán)節(jié)確認(rèn)了關(guān)系綁定都沒問題情況下還出現(xiàn) 客戶端FD 丟失,那么我想到 這可能是因為服務(wù)器被負(fù)載均衡 (SLB)了,無法測服復(fù)現(xiàn)是因為測試服是單機。

第二天一早, 為了驗證猜測,同事查看了在阿里云上的負(fù)載均衡服務(wù)配置,果然破案了?。?!這個項目此前一直是單機服務(wù),也不知道從何時開始 變成多節(jié)點服務(wù)了。

我來描述下為什么分布式服務(wù)的 WebSocket 會存在這種現(xiàn)象,而分布式服務(wù)的 HTTP 卻沒有這樣的問題呢?因為 WebSocket 有個用戶與客戶端標(biāo)識(FD)關(guān)系需要綁定,而 HTTP 服務(wù)一般是不需要關(guān)注客戶端標(biāo)識(FD)的。

WebSocket 服務(wù)端需要推送消息到用戶所連接的客戶端時,例如A、B兩臺服務(wù)器,用戶1連接到聊天室(服務(wù)器A),客服1也連接到聊天室(服務(wù)器B), 這種情況下 顯然用戶1發(fā)消息給客服1 是對牛彈琴了,因為用戶1發(fā)送消息后,服務(wù)器A會遍歷該服務(wù)器內(nèi)的所有用戶與客戶端標(biāo)識(FD),然后取出所有客服1的FD 進(jìn)行消息推送,而客服1連接的是服務(wù)器B,則對于用戶1來說 客服1是不在線的, 所以用戶1推送消息是推了個寂寞?。。。?再如 你的服務(wù)是支持用戶多設(shè)備、多平臺同時在線也是一樣的道理,這種情況下也就意味著可能用戶的客戶端標(biāo)識(FD)會同時分布在 服務(wù)器A、服務(wù)器B、服務(wù)器C …,那么用戶在其中一臺設(shè)備發(fā)送消息,在其他端登陸的該用戶都應(yīng)該要收到這條消息,單純地根據(jù)用戶所連接的服務(wù)去發(fā)送消息 那么其他端在線的該用戶都無法收到此消息了,群發(fā)也是一樣的道理。

多節(jié)點問題

在開始思考分布式會有什么問題時,先來回答一個問題: 服務(wù)端如何與客戶端交流?

在 WebSocket 服務(wù)端,每當(dāng)與客戶端連接成功后,會生成一個 唯一的客戶端標(biāo)識符 FD,WebSocket 會維護(hù)一個與客戶端所有連接的 Connections。在業(yè)務(wù)層,你需要將每個連接進(jìn)來的客戶端標(biāo)識(FD)與項目的用戶ID綁定起來,比如用 redis 將用戶和客戶端標(biāo)識(FD) 保存起來,當(dāng)客戶端斷開連接時解綁(刪除掉對應(yīng)的客戶端標(biāo)識(FD)),因為服務(wù)是用的PHP Swoole, 用 Swoole Table (服務(wù)進(jìn)程間內(nèi)存共享) 實現(xiàn)用戶與客戶端標(biāo)識(FD)綁定關(guān)系。這樣你就可以知道某個用戶在不在線,并且這個用戶的客戶端標(biāo)識(FD)有哪些,然后遍歷 Swoole Table 把用戶的所有客戶端標(biāo)識(FD)取出來循環(huán)推送消息給客戶端。

那如何給所有人廣播消息呢?

服務(wù)器只需要與它自身的所有客戶端連接 Server.Connections 挨個發(fā)消息就是廣播,所以它只是一個偽廣播: 我要給群里所有人發(fā)消息,但我不能在群里發(fā),只能挨個私發(fā)。

單節(jié)點

當(dāng)單節(jié)點時,流程如下:

 

這時所有用戶都能收到消息通知。

多節(jié)點

當(dāng)多節(jié)點時,就會有部分用戶無法正常收到通知 (就是我文中開頭所描述的現(xiàn)象),從以下流程圖中可以很清楚地看到問題所在:

 

負(fù)載到節(jié)點B 的所有用戶都沒有收到消息通知。

如何解決

說了這么多,怎么解決這個問題呢?

網(wǎng)上的很多教程,有些是通過 WebSocket 中間服務(wù)轉(zhuǎn)發(fā)器、網(wǎng)關(guān)轉(zhuǎn)發(fā)器 等實現(xiàn)方案,但這些實現(xiàn)方式有局限性,因為這些方案大部分是需要判斷用戶在哪臺服務(wù)器上(需要知道IP),然后轉(zhuǎn)發(fā)層將請求轉(zhuǎn)發(fā)到用戶所在服務(wù)器上。這種方案用戶單端登錄還好,如果用戶多端登錄 請求被轉(zhuǎn)發(fā)到多服務(wù)器上同時處理相關(guān)邏輯顯然是有問題的,比如新增數(shù)據(jù)、修改數(shù)據(jù)…這些操作等,這種架構(gòu)解決方案 用戶多點平臺登錄時調(diào)整復(fù)雜度會變得較高。

將 Swoole Table (服務(wù)進(jìn)程間內(nèi)存共享) 改造為 Redis 哈希 來實現(xiàn)用戶與客戶端標(biāo)識(FD)綁定關(guān)系,主要目的是在單節(jié)點處理邏輯的時候經(jīng)常需要判斷對端用戶是否在線,單服務(wù)內(nèi)的共享內(nèi)存并不能知道其他服務(wù)內(nèi)該用戶是否在線,所以這個方案不可取了。改用 分布式緩存 就可以判斷出對端用戶是否在線了。

分布式緩存實現(xiàn)用戶與客戶端標(biāo)識(FD)綁定關(guān)系大致做法為:

  1. 在服務(wù)啟動時創(chuàng)建一個 全局唯一ID,保證多服務(wù)下這個 ID的唯一性,比如啟動5個服務(wù)時,每個服務(wù)的ID都不能有相同,目的是用來分布式緩存的客戶端FD標(biāo)識所在的服務(wù)ID,當(dāng)然 你也可以使用IP作為唯一性(可能會更直觀點)。
  2. 將 唯一ID_FD 作為哈希鍵存儲,在某個事件或定時清除不活躍的哈希鍵。要當(dāng)前某個服務(wù)的所有哈希鍵的時候可以使用 hScan 循環(huán)迭代模糊匹配實現(xiàn),必要時使用 hGetAll 獲取所有哈希鍵值(并發(fā)高服務(wù) 在此提醒謹(jǐn)慎使用哈)。

多節(jié)點服務(wù)器就會有分布式問題,解決分布式問題就找一個大家都能找到的地,比如說 MQTT、Kafka、RabbitMQ 等消息中間件,另外使用 Redis 的發(fā)布訂閱(pubsub)功能 也一樣可以實現(xiàn),不過在此我選擇的是用 RabbitMQ 來實現(xiàn)。

改進(jìn)后流程圖如下:

負(fù)載均衡(SLB) 內(nèi)所有服務(wù)啟動時都綁定同一個RabbitMQ Fanout(廣播模式) 交換機, 如果該交換機不存在則創(chuàng)建。然后每個服務(wù)都生成一個唯一的該交換機隊列(生成的交換機隊列不能相同, 比如可以服務(wù)器1生成的隊列名為 S1, 服務(wù)器2生成的隊列名為 S2), 可以將生成的隊列設(shè)置為 auto_delete: true, 這樣就可以達(dá)到當(dāng) 隊列沒有消費者的時候該隊列會自動刪除, 服務(wù)重啟時又重新生成的效果。接下來就是每個服務(wù)都注冊該交換機隊列的監(jiān)聽消費,當(dāng)隊列的每一條息出棧時都會廣播到該交換機下的所有隊列(即所有服務(wù)的隊列監(jiān)聽事件都能收到PUSH進(jìn)來的消息)。客戶端請求到 負(fù)載均衡(SLB) 任意一臺服務(wù)器該服務(wù)器邏輯處理完后將要發(fā)送給客戶端的消息推送至 RabbitMQ 消息隊列消息隊列將該消息廣播到所有服務(wù)器的監(jiān)聽消費事件內(nèi)所有服務(wù)器的監(jiān)聽消費事件內(nèi) Redis hScan 迭代遍歷當(dāng)前服務(wù)內(nèi)所有客戶端連接,取出所有符合用戶ID對應(yīng)的客戶端標(biāo)識(FD)進(jìn)行推送消息。(并發(fā)高時對 Redis 沖擊很大,需要預(yù)估支撐力,對緩存哈希的讀要求隨并發(fā)高低而上升 O(n))

 

 

這種 WebSocket 分布式架構(gòu)解決方案同時 實現(xiàn)了支持單個用戶多設(shè)備、多平臺同時在線的場景,不需要知道有多少臺服務(wù)器(也就是說服務(wù)器可以無限動態(tài)擴容),不需要知道用戶對應(yīng)哪些服務(wù)器,也不需要知道各個服務(wù)器的IP地址,只需要處理各自服務(wù)器內(nèi)的監(jiān)聽消費隊列即可相對于一些通過搭建轉(zhuǎn)發(fā)服務(wù)器、網(wǎng)關(guān)服務(wù)器等實現(xiàn)的 WebSocket 分布式架構(gòu) 有著天然的優(yōu)勢,這些架構(gòu)解決方案要復(fù)雜很多,特別是要實現(xiàn)多設(shè)備、多平臺同時在線的場景時 更加、更加、更加復(fù)雜。

 

生活不易,如果您覺得這篇文章寫得不錯就動動手指幫忙點個贊吧!感恩各位~

分享到:
標(biāo)簽:WebSocket
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達(dá)人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定