Проблема с производительностью NodeJ - PullRequest
5 голосов
/ 06 мая 2011

Я создаю приложение статистики в реальном времени, используя NodeJs. В качестве прототипа я использую четырехъядерный процессор AMD Opteron на сервере RackSpace для теста с сервером nodejs с использованием NodeJs кластера (http://learnboost.github.com/cluster/) и MongoDb с использованием собственного драйвера nodejs.

По сути, я вставил код JS в проект моей компании, который доставляет контент для нескольких веб-сайтов клиентов. Этот код «пингует» мой сервер каждые 10 секунд, вызывая изображение и передавая параметры, которые я получаю на стороне сервера и вставляю (или обновляю) в коллекцию MongoDb. В «медленное» время дня я получаю около 3000 соединений (я получаю их с помощью команды netstat -natp на терминале) каждый раз, когда мой кластер использует около 25% каждого ядра (я получаю их с помощью команды «top»). ). Но в «напряженный» час я получаю около 7000+ соединений каждый раз, что сводит мой кластер с ума (около 80% + использование каждого ядра), и кажется, что со временем узел ухудшается. Это нормально? Или Nodejs должен обрабатывать эти попадания более «легким» способом? Если я использую Mongoose, производительность может увеличиться?

В случае, если вам интересно, что MongoDb использует около 4% одного ядра, это хорошо для меня (без указания индекса использование составляло около 50% +, но, по крайней мере, индекс решил эту проблему с производительностью).

Большое спасибо за терпение, Приветствия.

Edit:

Код, который делает вставку, выглядит следующим образом: 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');
      });
});

Ответы [ 6 ]

2 голосов
/ 07 мая 2011

Это нормально?

Зависит, соединения исчезают сами по себе?Они просто продолжают строить?Вы говорите о веб-соединении (http) или MongoDB?

Что говорят журналы mongod?Что говорят node журналы?

Сколько запросов вы получаете в секунду?

Или Nodejs должен обрабатывать эти обращения более «простым» способом?

Трудно сказать, не зная, что делает код.

Сколько одновременных подключений вы ожидаете от коробки?

Если я использую Mongoose, производительность может увеличиться?

Так что Mongoose на самом делеобъектная оболочка вокруг node-mongodb-native драйвера.Это не другой драйвер, это просто оболочка.

Эта оболочка добавит код к уже имеющемуся коду.Если у вас есть проблема с кодом, то добавление кода не гарантирует ее исправления.Если Мангуста действительно решит вашу проблему, то он делает что-то с подключениями, которыми вы не являетесь.В этом случае вам не обязательно нужен Mongoose, вам просто нужно более качественное управление соединениями.


Посмотрите, есть много потенциальных источников для вашей проблемы.

Единственный способ решить эту проблему - разбить кусочки и углубиться в детали.Места для начала: - правильно ли закрываются соединения с MongoDB (посмотрите журналы БД)?- есть ли в журналах другие ошибки?сделать то же самое для журналов узлов?- есть ли у вас графики использования памяти?кто занимает больше всего памяти?- когда вы получаете до 80% каждого ядра, какой процесс это делает?mongod?node?что-то еще?

Чтобы действительно помочь вам, нам нужно гораздо больше данных о том, что происходит с системой.

1 голос
/ 14 февраля 2012

Узел http по умолчанию поддерживает keep-alive. Это вызывает слишком много бесполезных соединений в вашем случае. Просто попробуйте добавить заголовок к disable Keep-Alive & mdash; обычный узел с кластером будет в порядке.

res.setHeader("Connection", "close")
1 голос
/ 11 мая 2011
if (!transparent) {
          console.log('!transparent');
          transparent = fs.readFileSync(__dirname + '/../../public/images/transparent.gif', 'binary');
      }

Как часто прозрачно ложно? Я не вижу его в коде. Вы блокируете весь процесс Node на синхронном диске IO, возможно, для каждого запроса. Зачем? Если вам нужно прочитать файл с диска, сделайте это асинхронно. Если файл статический и небольшой, возможно, вам следует загрузить его в память один раз.

1 голос
/ 06 мая 2011

Непрерывные запросы могут быть довольно дорогими, особенно если время ожидания между ними небольшое.В вашем случае вы принимаете от ~ 300-700 + одновременных запросов в секунду, и нагрузка на вашу систему может зависеть именно от того, что вы обрабатываете.Вы можете попытаться переключиться на Mongoose, однако я бы предпочел посмотреть на обработку и кэширование изображений, если это применимо для вашего сценария, поскольку БД, по-видимому, не является вашим узким местом (хотя может также возникнуть проблема с драйвером БД).

0 голосов
/ 19 марта 2012

Вы также можете просто подать этот прозрачный GIF из буфера, как здесь:

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

0 голосов
/ 12 мая 2011

Просто обновление:

Я отбросил кластер и поместил слой Nginx на сервер.Так что «деградация» заняла гораздо больше времени, но она все еще делает это, особенно потребляя много оперативной памяти системы.Есть какие-нибудь мысли?

И большое спасибо за все ответы!

Редактировать: Повторно провели некоторые тесты.Я думаю, что ОСНОВНАЯ ПРОБЛЕМА касается открытых связей.Когда я запускаю netstat на порту Nginx, он говорит как 2000 соединений.Когда я запускаю на каждом порту приложения nodejs, он говорит 2000 (или больше).По сути, мой «лучший вариант развития событий» заключается в том, что сумма открытых соединений в приложениях nodejs будет соответствовать открытым соединениям на порту Nginx, верно?Я думаю, что это главная проблема, которая влияет на огромные статусы "time_wait".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...