粘性负载平衡
如果计划在不同进程或计算机之间分配连接负载,则必须确保与特定会话ID关联的请求连接到发起它们的进程。
这是由于某些传输,如XHR轮询或JSONP轮询依赖于在“套接字”的生命周期内触发多个请求。未能启用粘性平衡将导致可怕的:
WebSocket握手期间出错:意外的响应代码:400
|
这意味着升级请求被发送到不知道给定套接字ID的节点,因此发送HTTP 400响应。
为了说明为什么需要这样做,请考虑向所有连接的客户端发送事件的示例:
io.emit('hi','all sockets');
|
有些客户可能会有一个活跃的双向通信渠道,就像WebSocket
我们可以立即写入,但其中一些可能正在使用长轮询。
如果他们使用长轮询,他们可能会或可能不会发送我们可以写入的请求。他们可能“介于”这些请求之间。在这些情况下,这意味着我们必须在此过程中缓冲消息。为了让客户端在发送请求时成功声明这些消息,最简单的方法是让他连接到路由到同一个进程。
如上所述,WebSocket
传输没有此限制,因为底层TCP连接在客户端和给定服务器之间保持打开。这就是为什么您可能会找到一些仅使用WebSocket
传输的建议:
常量客户= 10(“https://io.yourhost.com”,{ //警告:在这种情况下,不存在回退到长轮询 传输:[ “的WebSocket” ] //或[“的WebSocket”,' polling'],这是同样的事情 })
|
两者都意味着当无法建立websocket连接时,长轮询没有FALLBACK,这实际上是Socket.IO的关键特性之一。在这种情况下,您应该考虑使用原始WebSocket,或者像robust-websocket这样的瘦包装器。
要实现粘性会话,有两个主要解决方案:
-
根据客户的起始地址路由客户端
-
基于cookie路由客户端
NginX配置
在文件的http { }
部分中nginx.conf
,您可以声明一个upstream
包含Socket.IO进程列表的部分,以便在以下各项之间平衡负载:
http { server { listen 3000 ; server_name io.yourhost.com;
location / { proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for ; proxy_set_header Host $ host ;
proxy_pass http:// nodes;
#enable WebSockets proxy_http_version 1。1 ; proxy_set_header升级$ http_upgrade ; proxy_set_header连接“升级” ; } }
上游节点{ #启用基于IP ip_hash的粘性会话 ;
服务器 app01:3000 ; 服务器 app02:3000 ; 服务器 app03:3000 ; } }
|
请注意ip_hash
指示连接将是粘滞的指令。
确保您还在worker_processes
最顶层配置以指示NginX应该使用多少工作人员。您可能还想调整块中的worker_connections
设置events { }
。
例
Apache HTTPD配置
标题添加Set-Cookie “SERVERID = sticky。%{BALANCER_WORKER_ROUTE} e; path = /” env = BALANCER_ROUTE_CHANGED
BalancerMember “http:// app01:3000” route = app01 BalancerMember “http:// app02:3000” route = app02 BalancerMember “http:// app03:3000” route = app03 ProxySet stickysession = SERVERID Proxy>
BalancerMember “ws:// app01:3000” route = app01 BalancerMember “ws:// app02:3000” route = app02 BalancerMember “ws:// app03:3000” route = app03 ProxySet stickysession = SERVERID Proxy>
RewriteEngine On
RewriteCond %{HTTP:Upgrade} = websocket [NC]
RewriteRule /(.*)balancer:// nodes_ws / $ 1 [P,L]
RewriteCond %{HTTP:Upgrade}!= websocket [NC]
RewriteRule /(.* )balancer:// nodes_polling / $ 1 [P,L]
ProxyTimeout 3
|
例
HAProxy配置
#参考:http://blog.haproxy.com/2012/11/07/websockets-load-balancing-with-haproxy/
listen chat
bind *:80个
default_backend节点
后端节点
选项httpchk HEAD /健康
http检查期望状态200
cookie io前缀间接nocache#使用握手
服务器上设置的`io` cookie app01 app01:3000检查cookie app01
服务器app02 app02:3000检查cookie app02
服务器app03 app03:3000检查cookie app03
|
例
使用Node.JS群集
就像NginX一样,Node.JS通过该cluster
模块提供内置的集群支持。
Fedor Indutny创建了一个名为粘性会话的模块,确保文件描述符(即:连接)基于原始路由remoteAddress
(即:IP)进行路由。请注意,这可能会导致路由不平衡,具体取决于散列方法。
您还可以根据群集工作程序ID为群集的每个工作人员分配不同的端口,并使用上面可以找到的配置平衡负载。
在节点之间传递事件
现在你有多个Socket.IO节点接受连接,如果你想向每个人(甚至某个房间里的每个人)广播事件,你需要一些在进程或计算机之间传递消息的方法。
负责路由消息的接口就是我们所说的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 }));
|
然后是以下电话:
io.emit('hi','all sockets');
|
将通过Redis 的Pub / Sub机制广播到每个节点。
注意:使用Redis适配器时仍需要粘性会话。
如果您想从nonsocket.io进程向它传递消息,您应该查看“从外部世界发送消息”。