socket.io分布式

Posted 雪松

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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:

[js] view plain copy
 
  1. http.listen(4000, function(){  
  2.   console.log(‘listening on *:4000‘);  
  3. });  

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适配器:

[js] view plain copy
 
  1. var redis = require(‘socket.io-redis‘);  
  2. io.adapter(redis({ host: ‘localhost‘, port: 6379 }));  

5. 重启各个socket.io应用,进行测试。

 

其他注意点:

    • 由于nginx的反向代理机制和socket.io的自动重连机制,上述架构还具备高可用的特性,即当某个节点down机时,原先连接到该节点上的客户端会自动重连至其它节点上。

    • 节点的数量可以随时增减,不需要暂停服务,只需修改nginx配置即可。

    • nginx的ip_hash是基于ip的前三段进行计算的,也就是说ip只有D段不同的两台客户端一定会连接到同一台服务器上,这点测试的时候需要注意。

    • 可以通过redis的订阅发布服务来实现其他系统同集群的通信,完成集群的管理工作。

    • 由于是分布式环境,所以节点内存中存储的信息(如用户、房间信息)可以考虑持久化到redis或mongodb中。


以上是关于socket.io分布式的主要内容,如果未能解决你的问题,请参考以下文章

Socket.io 分布在不同的服务器上

socket.io如何进行分布式部署

socket.io:如何处理 4000 个用户?

Heroku 上的 Socket.io:客户端代码

HTTP 状态代码 200 但页面未加载 Node.js Socket.io -- 使用 Socket.io 的 Node.js 教程,Daniel Nill,fs.readFile(),socket

我应该在哪里为 socket.io 编写客户端代码?