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


11

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

前端服务器是一台8核机器,具有8 gigs 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个演出,奇怪的是,即使我完全重新启动整个应用程序,它也不会发布。仅当我重新启动服务器后才会释放!我真的不明白...

现在,我发现了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程序员,而不是sys admin,所以我不知道我应该为服务器承担多少负载,但可以肯定的是,它并没有达到应有的性能。否则该应用程序是稳定的,而最后一个问题使我无法交付已准备好的移动版本的应用程序,因为显然它们会带来更多的负载并最终使整个事情崩溃!

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


有什么办法可以从node.js中获得类似线程转储的东西吗?无限循环中可能有一些线程。另外,实际上使用cpu是什么?top当CPU使用率接近100%时,您会看到什么?
rvs

cpu完全由nodejs使用,当我运行top时,我看到节点进程占用了所有cpu。不知道我该如何从节点输出线程转储,说实话...
Franjanko

另一点要指出的是,大多数CPU时间似乎都
花在

至少有人知道我应该能够使用已有的服务器处理多少个并发连接吗?目前,我最多支持200个并发连接。这将帮助我估计距最佳配置还有多远……谢谢。
Franjanko 2013年

Answers:


10

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

问题出在我与socket.io一起使用的发布/订阅连接中,尤其是在socket.io用于处理套接字实例的进程间通信的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事件建立在连接上,除非每个连接都每次都销毁并重新创建,以清理它们。

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

干杯。


2
我的生产应用程序出现了似乎相同的问题,这也是服务器管理员角色的新问题。我遵循您在概念上所做的操作,但是我对如何执行操作有一些疑问-也许您可以在接受的答案中提供指向某些资源的链接?还是只是提供更多信息?特别是有关“但是后来我决定尝试为每个客户端创建2个新的Redis连接,以仅在其会话上处理其发布/订阅,然后在用户断开连接后关闭连接。”
toblerpwn13年

2

您有一些要转储的源代码吗?可能是到数据库的连接未关闭?等待永远不会关闭的HTTP连接的进程。

你可以张贴一些日志吗?

执行ps -ef并确保没有任何内容在运行。我已经看到Web进程留下的僵尸在您执行kill -9之前不会死亡。有时关机不起作用或不能完全起作用,并且那些线程或进程将容纳RAM,有时会容纳CPU。

这可能是代码中某处的无限循环,或者是处于数据库连接顶部的崩溃进程。

哪些NPM模块正在使用?他们都是最新的吗?

你在捕捉例外吗?参见:http : //geoff.greer.fm/2012/06/10/nodejs-dealing-with-errors/ 参见:https : //stackoverflow.com/questions/10122245/capture-node-js-crash-reason

一般提示:

http://clock.co.uk/tech-blogs/preventing-http-raise-hangup-error-on-destroyed-socket-write-from-crashing-your-nodejs-server

http://blog.nodejitsu.com/keep-a-nodejs-server-up-with-forever

http://hectorcorrea.com/blog/running-a-node-js-web-site-in-production-a-beginners-guide

/programming/1911015/how-to-debug-node-js-applications

https://github.com/dannycoates/node-inspector

http://elegantcode.com/2011/01/14/taking-baby-steps-with-node-js-debugging-with-node-inspector/


1

本身不是答案,因为您的问题比单答案指出问题更像是一个故事。

告诉我,我成功地用socket.io构建了一个node.js服务器,该服务器处理了超过100万个持久连接,平均消息有效负载为700字节。

1Gbps的网络接口卡在开始时就饱和了,我看到从发布事件到所有客户端的大量I / O等待。

从代理角色中删除nginx还返回了宝贵的内存,因为仅用一台服务器就可以达到一百万个持久连接,这是调整配置,应用程序和调整OS参数的艰巨任务。请记住,只有在有大量RAM的情况下才可以使用它(大约100万个websockets连接吃掉了约16GB的RAM,而使用node.js,我认为使用sock.js对于低内存消耗来说是理想的选择,但是就目前而言,socket.io消耗那么多)。

此链接是我达到与节点的连接数量的起点。除了它是一个Erlang应用程序之外,所有操作系统调优都几乎与应用程序无关,并且应被那些致力于许多持久连接(Websocket或长轮询)的人使用。

HTH,

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.