如何设置一个高需求的应用程序的node.js堆栈?

我目前正在使用超过25000人使用的Node.js堆栈应用程序,我们特别使用Sails.js框架,并且我们得到了MongoDB应用程序运行在具有30GB RAM的EC2实例,databse运行在Mongolab上基于AWS的集群位于EC2所在的同一区域。 我们甚至有一个1.5GB的Elastic Cache Redis实例存储。

所以我们面临的主要和巨大的问题是延迟 。 当我们达到请求应用程序并发用户的高峰时,我们得到了多个超时和启动应用程序达到超过7.5GB的内存,对HTTP的HTTP请求花费超过15秒(这是不可接受的),甚至当得到502和504响应nginx的。

我可以注意到Mongo写操作是我们的主要延迟问题,但是即使有需求峰值,GET请求也需要很长时间。 我无法访问生产服务器,我只有pm2(这实际上很棒)和New Relic警报获得了一个keymetrics监控工具。

所以,我想知道一些应对这些问题的路线图,也许应该提供更详细的信息,到目前为止,我可以说没有太多的用户时,应用程序似乎是稳定的。

什么是主要因素和设置要考虑?

到目前为止,我知道我应该做什么 ,但是我不确定细节和方式。

恕我直言:

  1. 尽可能caching。
  2. 延迟MongoDB写操作。
  3. 分离Mongo数据库,写入需求较高。
  4. 虚拟化?
  5. 调整节点设置。

在优化代码,我已经发布了另一个stackoverflow问题与我正在遵循的代码模式的一个例子。

你对生产应用有什么build议和意见?

基本上大部分的要点已经出现在答案中。 我只是总结一下。

要优化你的应用程序,你可以做几件主要的事情。

  1. 尝试将表单node.js移动到io.js它仍然具有更好的性能和最新的尖端更新。 (但仔细阅读有关实验function)。 或者至less从node.js v10v12 。 有很多性能优化。

  2. 避免使用使用I / O操作或使用大量数据的同步function。

  3. 从一个节点进程切换到集群系统。

  4. 检查你的应用程序内存泄漏。 我为node.js v12使用memwatch-next ,为node.js v10使用memwatch

  5. 尽量避免将数据保存到全局variables

  6. 使用caching。 对于应该可以在全球范围内访问的数据,您可以使用RedisMemcached也是一个很好的商店。

  7. 避免与async一起使用async 。 两个库都在做同样的事情。 所以不需要使用它们。 (我在你的代码示例中看到了这一点)。

  8. async.waterfallasync.parallel方法结合async.waterfall ,完成它。 例如,如果您需要从mongo中获取一些仅与用户相关的数据,则可以获取用户,然后并行获取所需的所有其他数据。

  9. 如果您正在使用sails.js确保它处于production模式。 (我假设你已经这样做了)

  10. 禁用所有你不需要的钩子。 在大多数情况下, grunt钩子是无用的。如果你的应用程序中不需要Socket.io ,可以使用.sailsrc文件来禁用它。 就像是:

    {“generators”:{“modules”:{}},“hooks”:{“grunt”:false,“sockets”:false}}

另一个可以禁用的钩子是: i18ncsrfcors 。 但只有当你不使用他们在你的系统。

  1. 禁用无用的全球化。 在config/globals.js 。 我假设_async services可以被默认禁用。 仅仅因为Sails.js使用老版本的lodashasync库,新​​版本的性能要好得多。

  2. 手动安装lodashasyncSails.js项目并使用新版本。 (看第11点)

  3. 将结果返回给用户后,可以进行一些“写入mongo”的操作。 例如:你可以调用res.view()方法,在Model.save()之前发送响应给用户,但是BUT代码将继续运行所有的variables,所以你可以保存数据到mongo DB。 所以用户在写操作期间看不到延迟。

  4. 你可以使用像RabbitMQ这样的队列来执行需要大量资源的操作。 例如:如果您需要存储大数据收集,您可以将其发送到RabbitMQ并向用户返回响应。 然后在“后台”处理广告商店数据中处理此消息。 它也可以帮助您扩展您的应用程序。

首先,确保你没有使用同步I / O。 如果你可以在io.js运行,那么如果你在下面的控制台警告中使用同步代码的话,会有警告--trace-sync-io标志( iojs --trace-sync-io server.js ): WARNING: Detected use of sync API

其次,找出为什么你的RAM使用率如此之高。 如果是因为大量的数据加载到内存中(XMLparsing,从MongoDB返回大量的数据等),你应该考虑使用streams 。 如果您的内存使用量非常高,V8垃圾收集(Google的JavaScript Node.js / io.js使用的JavaScript VM)可能会导致速度放慢。 更多信息: Node.js本周提示:pipe理垃圾收集和Node.js性能本周提示:堆分析

第三,尝试Node.js集群和MongoDB分片 。

最后,检查你是否使用或可以切换到MongoDB 3.x. 我们已经观察到一些显着的性能收益,从2.x升级到3.x。

对于Mongodb,您可以使用mongtop来查看哪些数据库是有争议的,每个数据库锁使用2.2+以上,如果数据库写入繁重的工作负载,读取将受到影响,因为mongodb使用写入器贪婪锁

而对于node.js,你可以检查是否有任何types的事件循环延迟,可以解释API请求延迟

 (function getEventLoopDelay() { var startTime = Date.now(); setTimeout(function() { console.log(Math.max(Date.now() - startTime - 1000, 0)); getEventLoopDelay(); }, 100); })();