Using multiple nodes

使用多个 node 实例

棘手的负载均衡

如果要在不同的进程或主机之间进行连接负载的分发,必须要确保带有特定 session id 的请求连接到产生该 id 的进程。

这是由于特定的传输方式(比如 XHR 轮询或 JSONP 轮询)依赖于在 “socket” 的声明周期中发送多个请求。

要阐明这么做的原因,可以参考下面的例子。这个例子是要在所有连接到服务器的客户端上触发一个事件:

io.emit('hi', 'all sockets'

可能有些客户端使用的是双向通信机制比如WebSocket,这样我们可以立即向其中写入消息。但是可能还有一些使用的是长轮询(long-polling)机制。

如果客户端使用了长轮询,它们不一定发送了可以向其中写入消息的请求。它们可能处于这些请求之间的阶段。这种情况下,我们需要在进程中缓存消息。为了让客户端能在发送请求时取回这些消息,最简单的方法就是让客户端连接到同一个进程上。

一种简单的方式是使用客户端的原始地址来进行路由。下面的例子使用了 NginX 服务器:

NginX 配置

nginx.conf文件的http { }块中,可以声明一个upstream块,里面声明一个需要进行负载均衡的 Socket.IO 进程列表:

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 { } 块中,还可以声明一个 server { } 来指向这个 upstream。为了让 NginX 支持并转发 WebSocket 协议,可以明确传递必需的 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; } }

请确保在最顶层配置了worker_processes参数,来指定 NginX 使用的工作进程数量。你还可以在events { }块中调节worker_connections设置。

使用 Node.JS 集群

和 NginX 一样, Node.JS 通过cluster模块提供了内置的集群支持。

Fedor Indutny 创建了一个sticky session模块。该模块确保文件描述符(也就是连接)可以通过来源的remoteAddress(也就是 IP)进行路由。

在 node 实例之间传递事件

假如有多个 Socket.IO 的 node 实例同时提供服务,而你要广播事件给所有人(或者特定房间里的所有人),你需要某种机制来在进程或主机之间传递消息。

这种消息路由的接口我们称之为Adapter(适配器)。你可以在socket.io-adapter之上实现自己的适配器(通过继承),或者直接使用我们提供的基于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 进程传递消息,可以看看“使用外部消息源”.