美文网首页程序员IT共论
用NodeJS+Nginx打造可扩展聊天服务

用NodeJS+Nginx打造可扩展聊天服务

作者: RavenZZ | 来源:发表于2016-04-09 01:31 被阅读1701次

    利用Nodejs实现即时通讯的选择最常见的就是socket.io,

    首先来说说socket.io

    优势:

    1. 上手容易

    2. 社区活跃(评价优秀开源项目的重要指标)

    3. 对开发者友好, 避免开发者适配IE等不支持websocket的浏览器

    4. 生态完整, 有对应Android,iOS SDK

    缺点:

    坑1. 一上生产环境就各种内存高或者cpu占用高

    坑2. 扩展性

    坑3. 从0.9x的不兼容性升级

    坑1 内存问题的解决

    socket.io在跑一段时间后, 内存占用并没有下来,猜测难道断开连接后,内存没有释放?  但通过heapdump分析快照,记录下三个状态进行对比,1>服务启动时 2>使用高峰时 3>使用低谷时 , 三者进行对比后发现并不是猜测的情况, socket.io自身的变量是已经销毁了的, 经历多次优化尝试后,原来是v8引擎并没有释放内存, 解决方案:启用--expose-gc,定时global.gc(),

    坑2 CPU问题的解决

    当时socket.io版本还为0.9.16, 并没有官方推荐的负载方案, 使用cluster做多进程时, 无论用redis store 还是 memory store都会造成nodejs服务或redis服务cpu高压力,导致服务响应变慢,解决方案:仅使用单进程,不做多进程负载(服务横向扩展后面会讨论)

    其余优化: v8引擎在64位机器侠默认在允许一个进程占用1.4G内存, 通过设置启动参数--max-old-space-size 和 --max-new-space-size 提高 v8 使用内存的上限,提高服务器内存使用率


    下面来说说服务最重要的横向扩展

    需求1. 用户可能同时打开多个网页和手机App, 用户的操作在多个页面都需要同步(如,切换聊天对象,发送消息等)

    需求2. 尽可能减少服务之间的消息同步

    现状1. 所有认证通过nodejs 读取用户请求cookie获取会话信息

    现状2. 常见的Nginx负载方案有round-robin,least-connected,ip-hash , 但这三种并不能很好的满足需求, 当backend增加时, 如果使用nodejs官方方案用所有消息在服务之间同步,会造成同步量非常大

    解决方案: 将会话前置到Nginx,并动态路由

    使用Nginx+lua(openresty)来读取会话信息, 并动态路由至指定backend服务,如 将user1的5个网页连接和1个app连接全部路由至server1

    这里的用户连接路由规则参照的是常见的数据库分表规则, 根据用户ID计算出对应chat server, 将单一用户连接锁定在单台服务上, 这样做的好处是, 不管是lua,nodejs或者其他语言都可简单的计算出用户对应连接的chat server, 有利于聊天服务与其他服务之间的对接.

    服务之间消息同步: 使用redis的pub/sub, 每台server订阅自己的频道, 当用户1要发送消息至连接到另外一台服务的用户2时,nodejs根据上面描述的路由规则计算出用户2对应的server, publish至用户2对应的server2, server2再将消息推送给user2

    写完才发现不能贴代码, 下次用markdown来写...

    参考链接:

    Nginx lua wiki

    https://www.nginx.com/resources/wiki/modules/lua/

    OpenResty 中文wiki

    https://github.com/iresty/nginx-lua-module-zh-wiki

    OpenResty 系列课程

    http://www.stuq.org/course/detail/1015

    socket.io

    socket.io

    相关文章

      网友评论

        本文标题:用NodeJS+Nginx打造可扩展聊天服务

        本文链接:https://www.haomeiwen.com/subject/xjnvlttx.html