node.js聊天室架构设计

 

2011-11-21 11:11:04|  分类: node |  标签:node.js聊天室  聊天室架构  node.js聊天室架构  node.jsmongodb  php聊天室  |字号 订阅

最近公司想在自己的项目中加入node.js项目,公司项目中有一个聊天室的东西,原来是基于flash socket制作的,服务器运营成本比较大,而且需要用户安装flash插件,对于使用ipad等平板用户比较悲剧。

公司的项目需要兼容IE6-8,所以web socket无法使用,只能使用常规的comet服务器推技术。而由于PHP在这方面天生短板,如果要服务端使用PHP的话,同时有1000人在一个服务器上聊天,服务器内存会被占用大半,而且频繁的释放建立fastcgi进程也在一定程度上影响效率。并且PHP不支持事件驱动,所以对于服务器推消息,只能去轮询数据库或缓存是否有新消息,这样数据库服务器压力也会倍增。

所以最后决定使用单进程,事件驱动的node.js作为服务端,不必每次重新建立进程处理请求,而且可以在有新消息时将消息推给客户端,不必去频繁扫描数据库。但是由于原本系统是基于php+flash socket的,所以一些如:用户信息,聊天室用户列表等,需要node.js异步去php接口获取,这样node.js异步的特性也发挥出来了。

我们的整体思路就是这样,上个架构图吧:

 


简单说明一下:
1、 客户端A、B、C、D、E分别连接到了nodejs聊天服务器1-4中,利用 长连接等待node.js 聊天服务器返回新消息。
2、 客户A向同在一个聊天室的客户B、客户C和客户E,发送了一条 新消息X
3、 Node.js聊天  服务器 1  将立即返回给同样 长连接在本服务器的客户E和客户A,并且同时异步将 新消息X 转发到 node.js数据库接口服务器
4、 注意:node.js聊天服务器和 node.js数据库接口服务器可以根据业务的处理量选择使用tcp不断连接或是http请求后断开连接
5、 Node.js接口服务器同时异步将 新消息X 存入mongodb数据库,并且同时根据 配置的地址池 将新消息广播转发到 node.js聊天服务器集群中。
6、 Node.js聊天服务器1-4接收到 新消息X,将 对 长连接在本服务器所有客户端信息和消息进行比对,判断是否需要返回 消息X长连接在本服务器的客户端,判断下来,客户端D不是消息接收方,node.js聊天服务器4 将 新消息X 抛弃,而B和C都获得了 新消息X。而node.js服务器 1 发现 新消息X 是本服务器发送的,则直接抛弃。
7、   另外这个 新消息X 中还会带有用户列表心跳包,即时更新用户活跃的时间戳,并且和PHP端保持用户列表的及时更新。

说明:
长连接等待:表示用户的ajax请求不立即返回,先挂起,等有新消息时再推给客户端。
负载均衡:在node.js聊天室服务器前可以部署一个nginx服务器用来做负载均衡,万一其中某一台node.js聊天室服务器宕机了,可以将其业务给其他服务器接管。

当然以上的架构比较大,可能部署的服务器比较多。但是扩展性和容错性比较好,属于花中等钱办中等事情。在网站日均pv 1000万以内,这套架构完全可以胜任了,估计以我们公司的业务几年内也突破不了,哈哈!

我们还有另外一套花小钱办中事情的方案,简称 方案-2。就是利用nginx 的 url_hash 模块,将同一聊天室的请求 反向代理 到同一台node.js聊天服务器,这样就可以将 node.js数据库接口服务器移走,node.js聊天服务器直接入库并且和PHP进行通信。
这样节约了服务器,而且由于在同一聊天室的客户端都在同一个服务器内,所以内存共享很容易就做到了,不必将消息转发,提高了效率。

不过 方案-2有一个严重的隐患,即利用url_hash做负载均衡后,期hash pool中有一台服务器宕机了,其业务并不会交由其他服务器接管,所以风险也较高,虽然可以做一个守护进程自动启动node.js主进程,也在node.js主进程中加入自动启动子进程,但是万一服务器断电了,还是会中断业务。

对于 方案-1方案-2需要公司权衡了,想花更少的钱达到同样的目的,那就必须承担一定的风险。不过如果公司业务预计增长很快,而且对于聊天系统的稳定性要求很高,那就不得不选择 方案-1了。

花絮:
在制作整个功能时踩了2个地雷,下面拿出来分享一下:
1、在我转发用户新消息时,出于方便,将用户的http请求头都转发了,所以出现PHP服务端返回一直是乱码,后来打印出请求头才发现,原来转发时增加了:“ Accept-Encoding : gzip, deflate”,所以nginx返回了gzip压缩以后的数据,转发时去掉那个http头就可以了。
2、在转发时一开始使用了post,结果造成了nginx 411错误,查阅资料发现是post请求的content-length没有设置,设置为POST body的字节数大小即可,当然后来我们改为了GET。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于构建一个基于 Node.js聊天室,你可以考虑使用以下的技术和库: 1. Express.js:这是一个流行的 Node.js Web 框架,可用于处理 HTTP 请求和路由。 2. Socket.IO:这是一个实时通信库,可以帮助你建立双向通信的 WebSocket 连接,用于实现实时聊天功能。 3. MongoDB:如果你需要持久化保存聊天记录或用户信息,可以考虑使用 MongoDB 这样的数据库。 4. Passport.js:这是一个用于身份验证和授权的库,可用于管理用户登录和访问控制。 5. Bootstrap 或其他前端框架:用于构建用户界面和响应式设计。 以下是一个简单的示例代码,使用 Express.js 和 Socket.IO 构建一个简单的聊天室: ```javascript // 1. 引入所需模块 const express = require('express'); const http = require('http'); const socketIO = require('socket.io'); // 2. 创建 Express 应用和 HTTP 服务器 const app = express(); const server = http.createServer(app); const io = socketIO(server); // 3. 设置静态文件目录 app.use(express.static(__dirname + '/public')); // 4. 处理 WebSocket 连接与消息 io.on('connection', (socket) => { console.log('A user connected'); // 监听客户端发送的消息 socket.on('chat message', (msg) => { console.log('message: ' + msg); // 广播消息给所有连接的客户端 io.emit('chat message', msg); }); // 监听客户端断开连接 socket.on('disconnect', () => { console.log('A user disconnected'); }); }); // 5. 启动服务器 const PORT = process.env.PORT || 3000; server.listen(PORT, () => { console.log('Server is running on port ' + PORT); }); ``` 上述代码中,客户端可以使用 Socket.IO 提供的 JavaScript 库与服务器进行实时通信,并监听 'chat message' 事件来发送和接收聊天消息。服务器将收到的消息广播给所有连接的客户端。 你可以根据自己的需求进一步扩展和定制这个聊天室,例如添加用户认证、保存聊天记录等功能。希望对你有所帮助!如果有其他问题,可以继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值