【问题标题】:NodeJs performance problemNodeJs 性能问题
【发布时间】:2011-08-19 20:47:24
【问题描述】:

我正在使用 NodeJs 构建一个实时统计应用程序。对于原型,我在 RackSpace 服务器中使用四核 AMD Opteron 来测试使用 Cluster NodeJs (http://learnboost.github.com/cluster/) 的 nodejs 服务器和使用本机 nodejs 驱动程序的 MongoDb。

基本上,我在我的公司项目中插入了一个 JS 代码,它为一堆客户的网站提供内容。此代码每 10 秒“ping”一次我的服务器,调用图像并传递我在服务器端获取的参数并在 MongoDb 集合中插入(或更新)。在一天中的“慢”时间里,我每次都会获得大约 3000 个连接(我使用终端上的 netstat -natp 命令获得这些连接),这使我的集群使用了每个核心的大约 25%(我使用“top”命令获得这些连接) )。但是在“忙碌”的时间里,我每次都会获得大约 7000 多个连接,这让我的集群变得疯狂(每个核心的使用率大约 80% 以上),而且似乎随着时间的推移,节点会降级。 这是正常的吗?还是 Nodejs 应该以更“简单”的方式处理这些命中?如果我使用 Mongoose,性能会提高吗?

如果您对 MongoDb 感到好奇,它使用了大约 4% 的内核,这对我来说很好(没有放置索引,使用率约为 50%+,但至少,索引解决了这个性能问题)。

非常感谢您的耐心等待, 干杯。

编辑:

进行插入的代码如下所示: db.open(function(err, db) { });

return connect.router(function(app){
    app.get("/pingserver/:clientid/:event/:cachecontrol", function(req, res, next){
    event:'+req.params.event + ', cachecontrol:' + req.params.cachecontrol);
        var timestamp = new Date(); 
          switch(req.params.event) {
          case 'load':
              var params = url.parse(req.url, true).query;

              db.collection('clientsessions', function(err, collection)         {
                try {

                    var client = {
                        id: req.params.clientid,
                        state: req.params.event + 'ed',
                        loadTime: timestamp.getTime(),
                        lastEvent: req.params.event,
                        lastEventTime: timestamp.getTime(),
                        lastEventDate: timestamp.toString(),
                        events: [{
                            event: req.params.event,
                            timestamp: timestamp.getTime(),
                            date: timestamp.toString()
                        }],
                        media: {
                            id: params.media.split('|')[0] || null,
                            title: unescape(params.media.split('|')[1]) || null
                        },
                        project: {
                            id: params.project.split('|')[0] || null,
                            name: unescape(params.project.split('|')[1]) || null
                        },
                        origin: req.headers['referer'] || req.headers['referrer'] || '',
                        userAgent: req.headers['user-agent'] || null,
                        userIp: req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress)),
                        returningUser: false
                    };
                }catch(e) {console.log(e);}       
                 collection.insert(client, function(err, doc) {
                 });
              });
              break;

          case 'ping':
              db.collection('clientsessions', function(err, collection) {
                  collection.update({id: req.params.clientid}, { 
                                                     $set : { lastEvent: req.params.event 
                                                             ,lastEventTime: timestamp.getTime(),lastEventDate: timestamp.toString()}
                                                   }, {}, function(err, doc) {});
              });
              break;

          default:
              db.collection('clientsessions', function(err, collection) {
                  collection.update({id: req.params.clientid}, { 
                                                     $set : {state: req.params.event+'ed'
                                                            , lastEvent: req.params.event 
                                                            , lastEventTime: timestamp.getTime()}
                                                   , $push : { events : { event: req.params.event, timestamp: timestamp.getTime(), date: timestamp.toString() } } }, {}, function(err, doc) {});
              });

              break;
          }

          if (!transparent) {
              console.log('!transparent');
              transparent = fs.readFileSync(__dirname + '/../../public/images/transparent.gif', 'binary');
          }
          res.setHeader('Content-Type', 'image/gif');
          res.setHeader('Content-Length', transparent.length);

          res.end(transparent, 'binary');
      });
});

【问题讨论】:

    标签: performance mongodb node.js mongoose


    【解决方案1】:

    连续请求可能会非常昂贵,尤其是在它们之间的超时时间很短的情况下。在您的情况下,您每秒接受约 300-700+ 个并发请求,您的系统负载可能取决于您正在处理的内容。您可以尝试切换到 Mongoose,但如果它适用于您的场景,我更愿意查看图像处理和缓存,因为 DB 似乎不是您的瓶颈(尽管 DB 驱动程序也可能是问题)。

    【讨论】:

    • 关于并发请求,它们在 3000 到 7000(或更多)之间。当我今天上班时,我看到服务器掉线了。它消耗了几乎所有的系统内存,我不得不重新启动它。无论如何,我会尝试猫鼬,谢谢你的提示。
    • 只是一个简单的问题:基本上我收到“ping”并将数据存储在 MongoDb 上。之后我必须关闭连接吗?另外,我在服务器启动时打开了与 MongoDb 的连接,并且永远不要关闭它。插入后会打开连接并关闭,提高性能吗?
    • 连接管理应该由drivers内的connection pools处理。尝试使用对所有请求使用单个非阻塞连接的 mongoose(如果它不是问题),看看情况是否发生了变化。
    【解决方案2】:

    这正常吗?

    取决于,连接会自行消失吗?他们只是继续建造吗?您说的是“网络连接”(http)还是 MongoDB 连接?

    mongod 日志说明了什么? node 日志说明了什么?

    你每秒收到多少请求?

    或者 Nodejs 应该以更“简单”的方式处理这些点击?

    如果不知道代码在做什么,很难说。

    您希望盒子可以处理多少个同时连接?

    如果我使用Mongoose,性能可以提高吗?

    所以 Mongoose 实际上是 node-mongodb-native 驱动程序的对象包装器。它不是一个不同的驱动程序,它只是一个包装器。

    包装器会将代码添加到您已有的代码中。如果您遇到代码问题,则不能保证添加代码会使问题变得更好。如果猫鼬确实解决了你的问题,那么它正在做一些你没有的连接。如果是这种情况,您不一定需要 Mongoose,您只需要更好的连接管理。


    看看有很多潜在的问题来源。

    解决这个问题的唯一方法是分解碎片并深入挖掘更多细节。开始的地方: - 与 MongoDB 的连接是否正确关闭(查看数据库日志)? - 日志是否包含任何其他错误? - 对节点日志做同样的事情吗? - 你有关于内存使用的图表吗?谁占用的内存最多? - 当你达到每个核心的 80% 时,哪个进程在执行此操作? mongod? node?还有什么?

    为了真正帮助您,我们需要更多关于系统运行情况的数据。

    【讨论】:

    • 谢谢,我会尝试深入研究并在此处发布。请注意:当 nodeJS 服务器启动时,我打开了与 Mongo 的连接,但我从不关闭它。这个可以吗?或者我应该在每个“ping”中打开连接并在更新/插入后关闭它?
    • 我认为你必须测试两种方式。我见过的唯一示例在您执行此操作时仅执行一次。您必须测试另一种方法以查看它是否正常工作。在撰写本文时,node-mongodb-native 没有连接池。你只有一个打开的连接。我不知道这如何与 Cluster 交互。
    • 也许这个开放的连接正在逐渐减少整个想法?好吧..我明天有一个演讲,所以我可以这样离开。之后我会尝试使用 Mongoose 查看日志。非常感谢您的回答!
    • 另一种选择是删除节点集群并尝试在其顶部使用 Nginx。有人做过吗?
    【解决方案3】:
    if (!transparent) {
              console.log('!transparent');
              transparent = fs.readFileSync(__dirname + '/../../public/images/transparent.gif', 'binary');
          }
    

    透明错误的频率是多少?我没有看到它在代码中定义。您正在阻止同步磁盘 IO 上的整个 Node 进程,可能针对每个请求。为什么?如果您必须从磁盘读取文件,请异步执行。如果文件是静态的并且很小,也许你应该把它加载到内存中一次。

    【讨论】:

    • 在我的一次重构中,我看到并修复了它。感谢您的提示!
    【解决方案4】:

    只是更新:

    我已经删除了集群并在服务器上放置了一个 Nginx 层。因此“降级”需要更长的时间,但它仍在这样做,特别是消耗了大量的系统 RAM 内存。 有什么想法吗?

    非常感谢所有的答案!

    编辑: 重新做了一些测试。我认为主要问题与打开的连接有关。当我在 Nginx 端口上运行 netstat 时,它显示为 2000 个连接。当我在每个 nodejs 应用程序端口上运行时,它会显示 2000(或更多)。基本上我的“最佳情况”是nodejs应用程序上的打开连接的总和将匹配Nginx端口上的打开连接,对吗?我认为这是主要问题,它影响了巨大的“time_wait”状态。

    【讨论】:

    • 基本上我有很多 TIME_WAIT 连接。
    • 大约 21k TIME_WAIT 连接。我猜这会消耗内存并降低服务器性能。
    【解决方案5】:

    节点的http 服务器默认保持活动状态。在您的情况下,它会导致太多无用的连接。只需尝试向disable Keep-Alive 添加一个标头——一个带有集群的普通节点就可以了。

    res.setHeader("Connection", "close")
    

    【讨论】:

      【解决方案6】:

      您可能还想从缓冲区中提供透明 gif,如下所示:

      https://gist.github.com/657246#comments

      【讨论】:

      • 实际上我采用了完全不同的方法。但是感谢您的帮助!
      猜你喜欢
      • 2012-11-07
      • 2014-02-16
      • 1970-01-01
      • 2019-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多