將碰到的情況整理分享,下次碰到可以少花些時間到處爬。
與 Redis 相關的環境
1. Sails Session 存放在 Redis。2. Kue (處理 job queue 的 node module) 使用 Redis。
事由
這次正式機發生 Redis 的記憶體空間不足,導致使用者無法登入,因為 Session 無法存入 Redis。
錯誤訊息
ERR command not allowed when used memory > 'maxmemory'
原因
1. maxmemory-policy 為預設值 volatile-lru (詳見附錄),若記憶體不足,只會回收有設有效期限的資料。
2. Kue 在丟 q:job 資料進 Redis 時並沒有設 Expire Set,我們也沒有程式或手動清除,
導致狀態為 complete 或 failed 的 q:job 和 q:search 的資料無限增加佔住記憶體。
解決方式
Redis
增加記憶體空間不足的 Error Handling,參考 連結 以及 官方 FAQ。What happens if Redis runs out of memory?
Redis will either be killed by the Linux kernel OOM killer, crash with an error, or will start to slow down. With modern operating systems malloc() returning NULL is not common, usually the server will start swapping and Redis performances will degrade so you'll probably notice there is something wrong. The INFO command will report the amount of memory Redis is using so you can write scripts that monitor your Redis servers checking for critical conditions. Redis has built-in protections allowing the user to set a max limit to memory usage, using the maxmemory option in the config file to put a limit to the memory Redis can use. If this limit is reached Redis will start to reply with an error to write commands (but will continue to accept read-only commands), or you can configure it to evict keys when the max memory limit is reached in the case you are using Redis for caching.
Kue
將狀態為 complete 和 failed 的 q:job 清除,可用方法如下:1. kue-sweeper
2. removeOnComplete(true)
queue.create( ... ).removeOnComplete( true ).save()在 0.8.4 版本之後才有實作,而我們使用的為 0.7.9,參考 連結一、連結二 以及 連結三。
3. 在每一個 job 建立之後收到該 job complete 事件就將該 job 資料移除,參考 連結。
jobs.on('job complete', function(id) { kue.Job.get(id, function(err, job) { setTimeout(function() { job.remove(); }, 60000); }); });
4. 定時移除已完成的 jobs,參考 連結。
var CLEANUP_TIME = 0.5 * 60 * 1000; var CLEANUP_INTERVAL = 0.1 * 60 * 1000; function cleanUpCompleteJobs() { var now = new Date().getTime(); Job.rangeByStatus('complete', 0, -1, 'asc', function (err, selectedJobs) { selectedJobs.forEach(function (job) { var created = job.created_at; if (now - created > CLEANUP_TIME) { job.remove(); } }); }); } setInterval(cleanUpCompleteJobs, CLEANUP_INTERVAL);
5. 在建立 job 時,帶入 expires 參數,並 setExpiration(),參考 連結。
暫時使用第四個方式並調整 Redis 記憶體不足空間回收機制 (maxmemory-policy),
測試新版本若銜接沒問題則升版使用第二個方式解決。
另外加上 Error Handling,
var queue = require('kue').createQueue(); queue.on('error', function( err ) { console.log( 'Oops... ', err ); });參考 連結。
附錄
1. 看目前 Redis 的記憶體使用狀況redis-cli info memory也可以只下
redis-cli info得到更多資訊。
較重要的為
used_memory:Redis 實際上使用掉的記憶體大小。
used_memory_rss:作業系統覺得 Redis 使用掉的記憶體大小。
mem_fragmentation_ratio:used_memory_rss 除以 used_memory。
中間的差距是存放在 Redis 的資料清掉之後留下的碎片記憶體空間。
至於記憶體空間的分配、使用方式視使用的 mem_allocator 而定,
最佳化方式可以參考 Memory-Optimization。
看目前設定
redis-cli config get maxmemory更改設定
redis-cli config set maxmemory 1234567
3. Redis 的 maxmemory-policy 設定
看目前設定redis-cli config get maxmemory-policy更改設定
redis-cli config set maxmemory-policy volatile-lru
maxmemory-policy 為 Redis 記憶體空間不足時,需要空間時的回收機制,分別有
noeviction:純粹回傳錯誤,不回收。
allkeys-lru:從最後一次使用時間離現在最久 (Less Recently Used) 的資料空間開始回收。
volatile-lru:同上,但只回收有設定有效期限 (Expire Set) 的資料,此為預設值。
allkeys-random:隨機回收。
volatile-random:同上,但只回收有設定有效期限的資料。
參考
https://github.com/Automattic/kue/issues/58
http://stackoverflow.com/a/10008222/1979454
冷知識
Redis port number 竟然是 MERZ 的手機按法來的!http://oldblog.antirez.com/post/redis-as-LRU-cache.html
沒有留言:
張貼留言