socket.io搭建分布式web推送服务器
骨头bone 发表于3年前
socket.io搭建分布式web推送服务器
  • 发表于 3年前
  • 阅读 7724
  • 收藏 275
  • 点赞 27
  • 评论 18

330元/年抢阿里云香港云服务器,节省80%出海成本>>>   

摘要: nodejs框架socket.io很好的帮我们解决了实时web推送时浏览器兼容的问题,但是单个socket.io实例承载能力有限,本文将介绍如何通过nginx+redis+socket.io的组合搭建一个分布式web推送服务器。

      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中。











共有 人打赏支持
粉丝 5
博文 1
码字总数 1006
评论 (18)
dsgfdsgf
<<最多只能容纳3000个long-polling方式的客户端进行连接>>
不会这么少吧
dingoo
由于负载用户登录到不同的节点上,然后如何通信这块写简单了
骨头bone

引用来自“2591349”的评论

<<最多只能容纳3000个long-polling方式的客户端进行连接>>
不会这么少吧
长轮训方式效率确实比较低,若浏览器支持websocket,并发数能有很大的提高。 这个测试结果在不同硬件上差别也很大。
骨头bone

引用来自“dingoo”的评论

由于负载用户登录到不同的节点上,然后如何通信这块写简单了
节点之间的消息推送用的是redis的消息订阅服务,socket.io-redis这个库利用socket.io开放的适配器接口结合redis完成了上述功能。
Angry_Snail
这不是 socket.io 官方文档里的东西么 ~~
Angry_Snail
这不是 socket.io 官方文档里的东西么 ~~
骨头bone

引用来自“Angry_Snail”的评论

这不是 socket.io 官方文档里的东西么 ~~
对啊,实践了下,踩了踩坑。 还有很多可改进的地方。
胡晓光
79支持!
骨头bone

引用来自“胡晓光”的评论

79支持!
roylieu
前面说的都没说到重点上,后面关于节点间通信和数据一致性方面一句话带过。
关于分布式的两个重点理论,一致性和网络分区只字未提。
roylieu
别随便就说系统是分布式的,分布式本身是一个险恶的话题,到现在大牛们也是在不断探索之中。

想深入了解的可以看:

http://product.china-pub.com/3768517 大规模分布式存储系统:原理解析与架构实战
http://product.china-pub.com/40882 分布式系统原理与范型(第2版)
骨头bone

引用来自“roylieu”的评论

前面说的都没说到重点上,后面关于节点间通信和数据一致性方面一句话带过。
关于分布式的两个重点理论,一致性和网络分区只字未提。
哥们,首先,推送服务器不是分布式存储引擎,为什么考虑数据一致性。这样的架构更偏向以集群的方式于扩展一群无状态服务器的处理能力。至于节点间通信,你要有心的话去研究socket.io-redis的源码,用的是redis的pubscribe和subscribe功能,可以理解为一人发布,多人接收的消息队列。
Nike527
Socket.io-Redis 能给点学习资料吗。网上的文档比较少,
newnoder
85
骨头bone

引用来自“Nike527”的评论

Socket.io-Redis 能给点学习资料吗。网上的文档比较少,
主要官网和源码,还有github
swingcoder
有用到生产环境?
骨头bone

引用来自“swingcoder”的评论

有用到生产环境?
恩,目前已经用到生产环境
Xiqincai
GoEasyWeb实时推送,轻松实现实时消息推送。 Web页面订阅(约5行代码),服务器端推送(2行代码)就可以轻松实现,而且在高并发时消息推送稳定。 自己完全可以只花五分钟写出属于自己的第一个实时推送功能!感兴趣的朋友可以到他们官网上看一下。https://goeasy.io
×
骨头bone
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: