2012-01-16 55 views
13

Trong ứng dụng node.js tôi đang sử dụng thư viện xếp hàng kue, được hỗ trợ bởi redis. Khi công việc hoàn tất, tôi xóa nó khỏi hàng đợi. Sau khi chạy khoảng 70.000 việc làm qua đêm, việc sử dụng bộ nhớ redis là khoảng 30MB. Có 18 công việc thất bại vẫn còn trong cơ sở dữ liệu, và chiều dài hàng đợi hiện tại là 0 - công việc được xử lý nhanh hơn so với hàng đợi. Redis không được sử dụng theo bất kỳ cách nào khác.Sử dụng thư viện "kue" được redis hỗ trợ trong node.js - tại sao việc sử dụng bộ nhớ Redis của tôi tiếp tục tăng?

Bất kỳ ý tưởng nào tại sao việc sử dụng bộ nhớ Redis tiếp tục tăng mặc dù tôi đang xóa các công việc đã hoàn thành? đang Coffeescript:

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 

Trả lời

0

Thực tế, sự cố xảy ra với phiên bản nút cũ hơn. Việc nâng cấp lên chuỗi 0.6.x đã giải quyết được vấn đề tiêu thụ mem.

19

Khi bạn có một vấn đề tiêu thụ bộ nhớ với một hệ thống xếp hàng, và bạn là 100% dương tính rằng tất cả các mặt hàng xếp hàng đợi đã được xóa khỏi cửa hàng và không ngồi vào một hàng đợi ngoại lệ/lỗi, thì nguyên nhân có thể xảy ra nhất là tỷ lệ xếp hàng cao hơn nhiều so với tỷ lệ khử.

Redis sử dụng bộ cấp phát bộ nhớ đa năng (jemalloc, ptmalloc, tcmalloc, v.v ...). Các bộ phân bổ này không nhất thiết phải cung cấp bộ nhớ cho hệ thống. Khi một số bộ nhớ được giải phóng, người cấp phát có xu hướng giữ nó (để tái sử dụng nó cho một phân bổ trong tương lai). Điều này đặc biệt đúng khi nhiều đối tượng nhỏ được phân bổ ngẫu nhiên, thường là trường hợp với Redis.

Hậu quả là mức tiêu thụ bộ nhớ cao nhất tại một thời điểm nhất định sẽ làm cho Redis tích lũy bộ nhớ và giữ nó. Bộ nhớ này không bị mất, bộ nhớ này sẽ được sử dụng lại nếu một mức tiêu thụ bộ nhớ khác xuất hiện. Nhưng từ quan điểm hệ thống, bộ nhớ vẫn được gán cho Redis. Đối với một hệ thống xếp hàng, nếu bạn xếp hàng nhanh hơn bạn có thể khử chúng, bạn sẽ có mức tiêu thụ bộ nhớ cao nhất.

Lời khuyên của tôi là đặt công cụ cho ứng dụng của bạn để tìm nạp và ghi lại độ dài hàng đợi vào các khoảng thời gian thường xuyên để kiểm tra sự tiến hóa của số mục trong hàng đợi (và xác định giá trị đỉnh).

Đã cập nhật:

Tôi đã thử nghiệm một vài điều có thể hiểu được những gì nó lưu trữ trong Redis. Trên thực tế, cấu trúc dữ liệu khá phức tạp (kết hợp các chuỗi, tập hợp, zsets và băm). Nếu bạn nhìn vào Redis, bạn sẽ tìm thấy những điều sau đây:

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) 

Tôi không biết Coffeescript ở tất cả, vì vậy tôi đã cố gắng để tạo lại vấn đề sử dụng đồng bằng cũ 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); 

Tôi chạy này mã, kiểm tra những gì còn lại trong Redis sau khi chế biến:

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" 

công việc Vì vậy, nó dường như hoàn thành được lưu giữ trong q: việc làm: đầy đủ và q: việc làm: X: hoàn thành mặc dù các công việc đã bị xóa. Tôi đề nghị bạn kiểm tra cardinality của các zsets trong trường hợp Redis của riêng bạn.

Giải thích của tôi là quản lý các zset này xảy ra sau sự kiện 'hoàn thành' được phát ra. Vì vậy, các công việc được gỡ bỏ một cách chính xác, nhưng id của họ được chèn vào trong những zsets ngay sau đó.

Giải pháp thay thế là tránh phải dựa vào các sự kiện cho mỗi công việc, mà là sử dụng các sự kiện trên hàng đợi để xóa công việc.Ví dụ, những sửa đổi sau đây có thể được thực hiện:

// 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(); 
} 

Sau khi sửa chữa các chương trình, nội dung trong Redis là tốt hơn nhiều:

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

Bạn có thể sử dụng một chiến lược tương tự từ Coffescript.

+0

Xin chào Didier - cảm ơn câu trả lời này, nhưng tôi không nghĩ rằng nó xác định được vấn đề. Tôi nên đã đề cập rằng chiều dài hàng đợi là số không. Thật dễ dàng để theo dõi trạng thái hàng đợi với thư viện kue này - nó bao gồm một máy chủ quản trị được tích hợp sẵn và giao diện người dùng. Tôi sẽ chỉnh sửa câu hỏi của mình để thêm thông tin này. – mainsocial

+0

Tôi đã cập nhật câu trả lời của mình cho phù hợp. –

+0

Didier - cảm ơn bạn đã điều tra. Tôi độc lập đến cùng một kết luận. Trong thực tế có một số lỗi trong mã kue mà tôi đã có thể sửa chữa. Tôi đã kiểm tra trong các bản sửa lỗi để ngã ba của tôi và thực hiện một yêu cầu kéo. – mainsocial

2

Rất vui khi thấy bạn đã khắc phục sự cố của mình. Trong mọi trường hợp, lần sau bạn gặp vấn đề về bộ nhớ với Redis, cổng gọi đầu tiên của bạn sẽ là lệnh "INFO" redis. Lệnh này sẽ cho bạn biết thông tin có giá trị như

Memory

used_memory: 3.223.928 used_memory_human: 3.07M used_memory_rss: 1.916.928 used_memory_peak: 3.512.536 used_memory_peak_human: 3.35M used_memory_lua: 37.888 mem_fragmentation_ratio: 0,59

Hoặc

Keyspace

db0: keys = 282, expires = 27, avg_ttl = 11335089640

Điều này rất tiện lợi để hiểu trạng thái bộ nhớ và không gian khóa tại bất kỳ thời điểm nào.

Các vấn đề liên quan