socket.io分佈式

    socket.io是目前較爲流行的web實時推送框架,其基於nodejs語言開發,底層用engine.io實現。 藉助nodejs語言異步的特性,其獲得了不錯的性能。但單個實例的socket.io依然承載能力有限,最多隻能容納3000個long-polling方式的客戶端進行連接。

     將socket.io進行分佈式擴展的難點有兩處:

1. 進行負載均衡時客戶端必須保證始終連到一個節點上

     如果客戶端採用long-polling長輪訓方式進行連接,則每次輪訓都會產生一個新的請求,若不進行限制。就有可能連接到集羣內新的 socket.io節點上,導致異常的發生。

     解決方法:使用nginx的ip_hash實現session sticky ,讓客戶端始終連接到集羣內一臺節點上。

2. 多個實例之間的消息推送

     當集羣內某臺節點想要向連接到集羣的所有客戶端發送消息時,某些客戶端因爲負載均衡時ip_hash可能被分配到了其他的節點上,這時就需要向其他節點發布推送消息,讓其他節點的同時向客戶端進行推送。

    解決方法:使用redis的發佈與訂閱功能與socket.io-redis開源庫,該庫在節點向客戶端羣發消息時會將該消息發佈到redis的訂閱隊列中,讓其他節點能夠訂閱到該消息,從而實現節點間消息推送。

       上圖是採用該架構的一個聊天服務器集羣示例,每個chatnode相當於一個socket.io實例,其中的chatModule負責客戶端連接,adminModule負責聊天服務器的管理功能。

       adminnode作爲整個集羣的管理節點,通過redis的消息訂閱功能來與各個chatnode通信, 並通過開放http接口來與外部系統進行交互。


準備安裝的軟件:

 nginxnodejsredis以及一個socket.io應用,如一個聊天服務器,例子請見官網這裏


具體步驟: 

1.將socket.io應用部署成兩個實例,如在同一臺主機上爲每個實例分配不同的端口號4000, 5000:

http.listen(4000, function(){
  console.log('listening on *:4000');
});

2.配置nginx文件,設置負載均衡proxy

upstream chat_nodes {
        ip_hash;
        server 127.0.0.1:4000;
        server 127.0.0.1:5000;
}

  以及反向代理設置 (注意爲了支持websocket協議,需將nginx升級至1.3.12版本以上

location / {
        proxy_pass              http://chat_nodes;
        proxy_set_header        Upgrade $http_upgrade;
        proxy_set_header        Connection "upgrade";
        proxy_http_version      1.1;
        proxy_set_header        Host $host;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }

  完成配置後,重啓nginx。

3.安裝nodejs模塊 socket.io-redis

sudo npm install socket.io-redis

4.在原來socket.io應用中初始化io的位置加入io的redis適配器:

var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));

5. 重啓各個socket.io應用,進行測試。


其他注意點:

  • 由於nginx的反向代理機制和socket.io的自動重連機制,上述架構還具備高可用的特性,即當某個節點down機時,原先連接到該節點上的客戶端會自動重連至其它節點上。

  • 節點的數量可以隨時增減,不需要暫停服務,只需修改nginx配置即可。

  • nginx的ip_hash是基於ip的前三段進行計算的,也就是說ip只有D段不同的兩臺客戶端一定會連接到同一臺服務器上,這點測試的時候需要注意。

  • 可以通過redis的訂閱發佈服務來實現其他系統同集羣的通信,完成集羣的管理工作。

  • 由於是分佈式環境,所以節點內存中存儲的信息(如用戶、房間信息)可以考慮持久化到redis或mongodb中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章