Использование библиотеки kue с поддержкой redis в файле node.js - почему мое использование памяти redis продолжает расти? - PullRequest
13 голосов
/ 16 января 2012

В приложении node.js я использую библиотеку очередей kue, которая поддерживается redis. Когда работа завершена, я удаляю ее из очереди. После выполнения около 70000 заданий за ночь использование памяти Redis составляет около 30 МБ. В базе данных по-прежнему оставалось 18 невыполненных заданий, и длина очереди в настоящее время равна нулю - задания обрабатываются быстрее, чем в очереди. Redis не используется никаким другим способом.

Есть идеи, почему использование памяти redis продолжает расти, хотя я удаляю завершенные задания? Кофейный код:

gaemodel.update = (params) ->
  job = jobs.create "gaemodel-update", params 
  job.attempts 2
  job.save()
  job.on "complete", ->
    job.remove (err) ->
      throw err if err
      console.log 'completed job #%d', job.id

Ответы [ 3 ]

19 голосов
/ 17 января 2012

Если у вас есть проблема с использованием памяти системой очередей, и вы на 100% уверены, что все элементы из очереди были удалены из хранилища и не помещаются в очередь исключений / ошибок, то наиболее вероятной причиной является На самом деле, скорость очереди намного выше, чем скорость ожидания.

Redis использует распределитель памяти общего назначения (jemalloc, ptmalloc, tcmalloc и т. Д.). Эти распределители не обязательно возвращают память системе. Когда некоторая память освобождается, распределитель стремится сохранить ее (чтобы повторно использовать для будущего выделения). Это особенно верно, когда много мелких объектов расположены случайным образом, как это обычно бывает с Redis.

Следствием этого является то, что пик потребления памяти в данный момент времени приведет к тому, что Redis накопит память и сохранит ее. Эта память не теряется, она будет использоваться повторно, если произойдет еще один пик потребления памяти. Но с системной точки зрения память все еще отводится Redis. Для системы очередей, если вы ставите элементы в очередь быстрее, чем вы в состоянии вывести их в очередь, у вас будет такой пик потребления памяти.

Я бы посоветовал вашему приложению извлекать и регистрировать длину очереди через регулярные промежутки времени, чтобы проверять эволюцию количества элементов в очереди (и определять пиковое значение).

Обновлен:

Я протестировал несколько вещей с помощью kue, чтобы понять, что он хранит в Redis. На самом деле, структура данных довольно сложна (смесь строк, наборов, zsets и хэшей). Если вы посмотрите на Redis, вы найдете следующее:

q:job:nnn             (hash, job definition and properties)

q:search:object:nnn   (set, metaphone tokens associated to job nnn)
q:search:word:XXXXX   (set, reverse index to support job full-text indexing)

q:jobs:inactive       (zset, all the unprocessed jobs)
q:jobs:X:inactive     (zset, all the unprocessed jobs of job type X)

q:jobs:active         (zset, all the on-going jobs)
q:jobs:X:active       (zset, all the on-going jobs of job type X)

q:jobs:complete       (zset, all the completed jobs)
q:jobs:X:complete     (zset, all the completed jobs of job type X)

q:jobs:failed         (zset, all the failed jobs)
q:jobs:X:failed       (zset, all the failed jobs of job type X)

q:jobs:delayed        (zset, all the delayed jobs)
q:jobs:X:delayed      (zset, all the delayed jobs of job type X)

q:job:types           (set, all the job types)
q:jobs                (zset, all the jobs)

q:stats:work-time     (string, work time statistic)
q:ids                 (string, job id sequence)

Я вообще не знаю Coffeescript, поэтому я попытался воспроизвести проблему, используя простой старый Javascript:

var kue = require('kue'),
    jobs = kue.createQueue();

jobs.process( 'email', function(job,done) {
  console.log('Processing email '+JSON.stringify(job) )
  done();
});

function create_email(i) {
  var j = jobs.create('email', {
    title: 'This is email '+i
    , to: 'didier'
    , template: 'Bla bla bla'
  });
  j.on('complete', function() {
    console.log('complete email job #%d', j.id);
    j.remove(function(err){
      if (err) throw err;
      console.log('removed completed job #%d', j.id);
    });
  });
  j.save();
}

for ( i=0; i<5; ++i )
{
   create_email(i);
}

kue.app.listen(8080);

Я запустил этот код, проверяя, что осталось в Redis после обработки:

redis 127.0.0.1:6379> keys *
1) "q:ids"
2) "q:jobs:complete"
3) "q:jobs:email:complete"
4) "q:stats:work-time"
5) "q:job:types"
redis 127.0.0.1:6379> zrange q:jobs:complete 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

Таким образом, завершенные задания сохраняются в q: jobs: complete и q: jobs: X: complete, несмотря на то, что задания были удалены. Я предлагаю вам проверить мощность этих zsets в вашем собственном экземпляре Redis.

Мое объяснение состоит в том, что управление этими zset происходит после того, как испущено 'завершенное' событие. Таким образом, задания корректно удаляются, но их идентификаторы вставляются в эти zsets сразу после.

Обходной путь - избегать полагаться на события для каждой работы, а вместо этого использовать события для каждой очереди для удаления работ. Например, могут быть сделаны следующие модификации:

// added this
jobs.on('job complete', function(id) {
  console.log('Job complete '+id )  
  kue.Job.get(id, function(err, job) {
     if (err) return;
     job.remove(function(err){
        if (err) throw err;
        console.log('removed completed job #%d', job.id);
     });
  });  
});

// updated that
function create_email(i) {
  var j = jobs.create('email', {
    title: 'This is email '+i
    , to: 'didier'
    , template: 'Bla bla bla'
  });
  j.save();
}

После исправления программы содержимое в Redis намного лучше:

redis 127.0.0.1:6379> keys *
1) "q:stats:work-time"
2) "q:ids"
3) "q:job:types"

Вероятно, вы можете использовать аналогичную стратегию из Coffescript.

2 голосов
/ 24 января 2014

Рад видеть, что вы исправили свою проблему. В любом случае, в следующий раз, когда у вас возникнет проблема с памятью в Redis, ваш первый порт вызова должен быть командой redis «INFO». Эта команда расскажет вам ценную информацию, такую ​​как

Память

used_memory: 3223928 used_memory_human: 3.07M used_memory_rss: 1916928 used_memory_peak: 3512536 used_memory_peak_human: 3.35M used_memory_lua: 37888 mem_fragmentation_ratio: 0,59

Или

1009 * пространство ключей * DB0: клавиши = 282, истекает = 27, avg_ttl = 11335089640 Что очень удобно для понимания состояния вашей памяти и пространства клавиш в любой момент.

0 голосов
/ 03 мая 2012

На самом деле проблема была в более старой версии узла.Обновление до цепочки 0.6.x решило проблемы потребления памяти.

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