当前位置: 首页>>技术教程>>正文


node.js,mongodb,redis,ubuntu生产性能下降,RAM可用,CPU 100%

, , , ,

问题描述

正如问题标题所暗示的那样,我很难确定可以对我的应用程序进行哪些改进(或在os,ubuntu中进行了调整)以达到可接受的性能。但首先,我将解释该体系结构:

front-end服务器是一台8核计算机,具有8 Gb RAM,运行Ubuntu 12.04。该应用程序完全用javascript编写,并在node.js v 0.8.22中运行(由于某些模块似乎抱怨较新版本的节点),我使用nginx 1.4将来自端口80和443的http通信代理到受管理的8个节点工作程序并开始使用节点集群api。我使用最新版本的socket.io 0.9.14来处理websocket连接,在该接口上,我仅启用了websockets和xhr-polling作为可用传输。在这台机器上,我还运行了Redis(2.2)的实例。

我将持久数据(例如用户和乐谱)存储在mongodb(3.6)上的第二台服务器上,该服务器具有4gigs RAM和2个内核。

该应用程序已投入生产数月之久(直到几周前才在一个盒子上运行),每天约有1.8万用户在使用。除以下一个主要问题外,它始终运行良好:性能下降。使用后,每个进程使用的cpu数量会增加,直到它使worker饱和(不再处理请求)为止。我已经临时解决了它每分钟检查一次每个工作人员使用的cpu的问题,并在达到98%时重新启动它。因此,这里的问题主要是cpu,而不是RAM。自从我更新到socket.io 0.9.14(较早的版本正在泄漏内存)以来,RAM不再是问题,因此我怀疑这是一个内存泄漏问题,尤其是因为现在它是CPU增长相当快的原因(我必须每天重新启动每个工人大约10-12次!)。说实话,使用中的RAM也会增长,但是会非常缓慢,每使用2-3天就会增加1 GB,奇怪的是,即使我完全重新启动整个应用程序,它也不会释放。仅当我重新启动服务器后才会释放!我真的不明白…

现在,我发现nodefly很棒,因此我终于可以看到生产服务器上发生了什么,而且已经收集了几天的数据。如果有人想查看图表,我可以给您访问权限,但是基本上,我可以看到我有80到200个并发连接!我期望node.js处理数千个请求,而不是数百个请求。同样,http流量的平均响应时间在500到1500毫秒之间浮动,我认为这确实很多。同样,在此时有1300位用户在线的时刻,这是“ ss -s”的输出:

Total: 5013 (kernel 5533)
TCP:   8047 (estab 4788, closed 3097, orphaned 139, synrecv 0, timewait 3097/0), ports 0

Transport Total     IP        IPv6
*         5533      -         -
RAW       0         0         0
UDP       0         0         0
TCP       4950      4948      2
INET      4950      4948      2
FRAG      0         0         0

这表明我在timewait中有很多关闭的连接。我已将打开的最大文件数增加到999999,这是ulimit -a的输出:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 63724
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 999999
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 63724
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

因此,我认为问题可能出在HTTP流量上,由于某些原因,该流量会导致可用的端口/套接字(?)饱和,但是对我来说没有任何意义:为什么当我重新启动工作线程时,所有客户端在几秒钟内重新连接,工人的CPU上的负载下降到1%,并且能够正确处理请求,直到大约1小时(在高峰时间)饱和为止?

我主要是一名JavaScript程序员,而不是系统管理员,所以我不知道我应该为服务器承担多少负载,但可以肯定的是,它并没有达到应有的性能。否则该应用程序是稳定的,而最后一个问题使我无法交付已准备好的移动版本的应用程序,因为显然它们会带来更多的负载并最终使整个事情崩溃!

希望有明显的事情我做错了,有人会帮助发现它…随时向我询问更多信息,对于这个问题的时长我感到抱歉,但我相信这是必要的…提前致谢!

最佳方法

经过几天的反复试验和错误,我很高兴地说出我已经了解了瓶颈所在,并将其张贴在这里,以便其他人可以从我的发现中受益。

问题出在我与socket.io一起使用的发布/订阅连接中,尤其是在socket.io用于处理套接字实例的inter-process通信的RedisStore中。

在意识到我可以使用redis轻松实现自己的pub /sub版本后,我决定尝试一下,并从socket.io中删除了redisStore,将其保留为默认的内存存储(我不需要广播到所有连接的客户端,但仅在可能连接不同进程的2个不同用户之间)

最初,我只声明了2个全局Redis连接x进程来处理每个连接的客户端上的pub /sub,并且该应用程序使用的资源较少,但是我仍然受到CPU使用率持续增长的影响,因此没有太大变化。但是后来我决定尝试为每个客户端创建2个新的Redis连接以仅在其会话上处理其发布/订阅,然后在用户断开连接后关闭连接。然后在生产中使用一天后,CPU的使用率仍为0-5%…宾果!没有进程重新启动,没有错误,没有我期望的性能。现在我可以说node.js令人赞叹,很高兴为构建此应用程序选择了它。

幸运的是,redis已被设计为可以处理许多并发连接(与mongo不同),默认情况下,它的设置为10k,在单个redis实例上为大约5k的并发用户留出了空间,这对我来说已经足够了,但是我我已经读到它最多可以推到64k并发连接,所以我认为这种架构应该足够牢固。

在这一点上,我正在考虑实现某种类型的连接池来进行redis,以进一步优化它,但不确定是否不会再次导致pub /sub事件建立在连接上,除非每个连接都每次都销毁并重新创建,以清理它们。

无论如何,感谢您的回答,如果您有其他建议,我很想知道您的想法。

干杯。

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/9678.html,未经允许,请勿转载。