前言
項目中有即時聊天的需求,經過調研我們採用了
socket.io自己實現了一個聊天服務器。開始的一段時間由於用戶不是很多,消息的發送接收都還算流暢,最近隨著在線用戶數量飆升,每過一段時間就會發生髮送消息卡頓和接收消息延時的問題,最後只能通過重啟socket服務來暫時解決問題。
那有沒有辦法從根本上解決這個問題呢?
目錄
- 什麼是socket.io?
- 用socket.io實現一個簡易的即時聊天應用
- socket.io支持分佈式部署嗎?
- 總結
什麼是socket.io?
在介紹什麼是socket.io之前,不得不先提一下WebSocket。
我們都知道HTTP協議是一種單向的網絡通信協議,服務端只能被動響應來自客戶端的請求,卻不能主動向客戶端推送數據。
在WebSocket技術沒有出現之前,如果要開發一個需要實時獲取服務端數據的Web應用,常見有以下兩種方式:ajax輪詢和Long Polling。
- ajax輪詢的原理其實很簡單,就是讓客戶端每隔一小段時間就主動向服務端發送一次請求,如果有新數據客戶端就把它顯示出來。
- 可以看出不管有沒有新數據,ajax輪詢都會定時向服務端發起請求,這會導致服務端不必要的性能消耗,Long Polling就是對ajax輪詢的一種改進。客戶端向服務端發送請求,服務端不會立即就響應客戶端而是會先保持住此次連接,直到有新的數據時才會返回,客戶端接收到數據之後再立即發送一個新的請求給服務端,並不斷得重複這一過程。
可以看出這兩種方式都需要不斷的建立連接,但是建立連接是一個比較消耗性能的操作,這個時候如果有一個新的通信協議可以支持客戶端和服務端雙向通信就好了,所以WebSocket應運而生。
WebSocket是HTML5新增的一種通信協議。WebSocket協議是一種支持雙向通信的協議,它和HTTP協議一樣通過TCP來進行數據傳輸,但是WebSocket又不同於HTTP:
- WebSocket是一種支持雙向通信的協議,雙方在建立連接後都能主動向對方發送或接收數據。
- 客戶端和服務端要想進行WebSocket通信必須先握手交換信息,成功之後才能進行通信。
說了這麼多,那麼WebSocket跟socket.io又是什麼關係呢?
一直以來我都以為socket.io只是WebSocket協議的一種實現而已,深入之後才發現這種觀點不完全正確。
socket.io是一個基於Node.js技術和WebSocket 協議開發的實時的,可雙向通信的和基於事件的的開源通信框架。
WebSocke是HTML5新推出的協議,主流瀏覽器對它的支持還不是很完善,所以socket.io不僅僅實現了WebSocket協議,除此之外它還支持一些其他的通信方式,比如前面我們提到的ajax輪詢和Long Polling等,可以根據瀏覽器的支持程度切換不同的通信方式。
用socket.io實現一個簡易的即時聊天應用
接下來我們就是使用socket.io來實現一個簡易的即時聊天的web應用。
先來看一下效果:
下面簡單介紹一下實現方式,主要分為客戶端和服務端兩個部分。
服務端核心代碼:
服務端主要定義了3個監聽事件,分別用來監聽客戶端的加入群聊、發送消息和離開群聊事件,服務端在監聽到事件後會再通過broadcast.emit方法將消息向全體用戶廣播。
客戶端核心代碼:
主要流程:
- 向socket服務端請求連接;
- 自己向服務端發送加入群聊請求;
- 監聽服務端廣播的其他用戶加入群聊消息;
- 監聽服務端廣播的用戶聊天信息;
- 監聽服務端廣播的用戶離開群聊消息;
socket.io支持分佈式部署嗎?
socket服務端維護連接是一個十分消耗性能的操作,那麼大量的連接必然會給服務器帶來非常大的性能壓力,當單臺socket服務器支撐不了時該怎麼辦呢?
解決方案其實也很簡單:分而治之 ,我們可以將多個socket服務端組成負載均衡集群,再將連接平均分配到每個服務端。
有人也許會提出疑問:多個socket服務端之間怎麼通信?比如用戶1連接到了socket服務端1,用戶2連接到了socket服務端2,那麼用戶1發的消息怎麼廣播到socket服務端2呢?
這裡就需要提一下Redis了,對你沒看錯,就是那個用作緩存的Redis。
其實Redis除了當作緩存使用之外,它還有一個非常厲害的功能:發佈/訂閱。
Redis的發佈訂閱機制包括三個部分:發佈者、訂閱者和頻道。 發佈者將消息發送到某個頻道,那麼Redis服務器就會主動將消息推送到訂閱了這個頻道的所有訂閱者。
socket.io正式利用Redis的發佈訂閱機制來支持分佈式部署的:
當客戶端1通過emit觸發了一個事件到socket服務端1,socket服務端1將這個消息發送到Redis的某個頻道,訂閱了這個頻道的socket服務端2就會收到這個消息,socket服務端2再向連接它的用戶廣播就行了。
代碼增加reids和socket.io-redis模塊:
總結
socket.io是一個基於Node.js技術和WebSocket協議開發的實時的,可雙向通信的和基於事件的的開源通信框架。除此之外它還兼容ajax輪詢和Long Polling等前後端通信方式,我們可以根據瀏覽器的支持程度進行自由切換。
socket.io非常適合客戶端和服務端需要進行實時通信的場景,它利用Redis的發佈訂閱機制可以實現分佈式部署,這讓socket服務端橫向擴展變得很加容易。
“分享知識,收穫快樂”
我是一名程序員,喜歡我的文章歡迎 關注 及 轉發,我會經常與大家分享一些工作當中的編程技巧與經驗。