如果要在不同的進(jìn)程或主機(jī)之間進(jìn)行連接負(fù)載的分發(fā),必須要確保帶有特定 session id 的請(qǐng)求連接到產(chǎn)生該 id 的進(jìn)程。
這是由于特定的傳輸方式(比如 XHR 輪詢或 JSONP 輪詢)依賴于在 “socket” 的聲明周期中發(fā)送多個(gè)請(qǐng)求。
要闡明這么做的原因,可以參考下面的例子。這個(gè)例子是要在所有連接到服務(wù)器的客戶端上觸發(fā)一個(gè)事件:
io.emit('hi', 'all sockets');
可能有些客戶端使用的是雙向通信機(jī)制比如 WebSocket
,這樣我們可以立即向其中寫入消息。但是可能還有一些使用的是長(zhǎng)輪詢(long-polling)機(jī)制。
如果客戶端使用了長(zhǎng)輪詢,它們不一定發(fā)送了可以向其中寫入消息的請(qǐng)求。它們可能處于這些請(qǐng)求之間的階段。這種情況下,我們需要在進(jìn)程中緩存消息。為了讓客戶端能在發(fā)送請(qǐng)求時(shí)取回這些消息,最簡(jiǎn)單的方法就是讓客戶端連接到同一個(gè)進(jìn)程上。
一種簡(jiǎn)單的方式是使用客戶端的原始地址來(lái)進(jìn)行路由。下面的例子使用了 NginX 服務(wù)器:
在 nginx.conf
文件的 http { }
塊中,可以聲明一個(gè) upstream
塊,里面聲明一個(gè)需要進(jìn)行負(fù)載均衡的 Socket.IO 進(jìn)程列表:
upstream io_nodes {
ip_hash;
server 127.0.0.1:6001;
server 127.0.0.1:6002;
server 127.0.0.1:6003;
server 127.0.0.1:6004;
}
注意 ip_hash
指令表明這些連接是持久的。
同樣在 http { }
塊中,還可以聲明一個(gè) server { }
來(lái)指向這個(gè) upstream。為了讓 NginX 支持并轉(zhuǎn)發(fā) WebSocket
協(xié)議,可以明確傳遞必需的 Upgrade
消息頭:
server {
listen 3000;
server_name io.yourhost.com;
location / {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_pass http://io_nodes;
}
}
請(qǐng)確保在最頂層配置了 worker_processes
參數(shù),來(lái)指定 NginX 使用的工作進(jìn)程數(shù)量。你還可以在 events { }
塊中調(diào)節(jié) worker_connections
設(shè)置。
和 NginX 一樣, Node.JS 通過(guò) cluster
模塊提供了內(nèi)置的集群支持。
Fedor Indutny 創(chuàng)建了一個(gè) sticky session 模塊。該模塊確保文件描述符(也就是連接)可以通過(guò)來(lái)源的 remoteAddress
(也就是 IP)進(jìn)行路由。
假如有多個(gè) Socket.IO 的 node 實(shí)例同時(shí)提供服務(wù),而你要廣播事件給所有人(或者特定房間里的所有人),你需要某種機(jī)制來(lái)在進(jìn)程或主機(jī)之間傳遞消息。
這種消息路由的接口我們稱之為 Adapter
(適配器)。你可以在 socket.io-adapter 之上實(shí)現(xiàn)自己的適配器(通過(guò)繼承),或者直接使用我們提供的基于 Redis 的適配器: socket.io-redis:
var io = require('socket.io')(3000);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
如果你需要從非 socket.io 進(jìn)程傳遞消息,可以看看“使用外部消息源”.
更多建議: