按Redis官網說法:對於設置了過期時間的key,有2種清理機制,原文如下:
How Redis expires keys Redis keys are expired in two ways: a passive way, and an active way. A key is passively expired simply when some client tries to access it, and the key is found to be timed out. Of course this is not enough as there are expired keys that will never be accessed again. These keys should be expired anyway, so periodically Redis tests a few keys at random among keys with an expire set. All the keys that are already expired are deleted from the keyspace. Specifically this is what Redis does 10 times per second: Test 20 random keys from the set of keys with an associated expire. Delete all the keys found expired. If more than 25% of keys were expired, start again from step 1. This is a trivial probabilistic algorithm, basically the assumption is that our sample is representative of the whole key space, and we continue to expire until the percentage of keys that are likely to be expired is under 25% This means that at any given moment the maximum amount of keys already expired that are using memory is at max equal to max amount of write operations per second divided by 4.
一、被動清理:
當這個key被訪問(比如:GET)時,如果發現已過期,redis會清理
二、主動清理:
2.1 大概1秒10次(即:約每100ms 執行1次)
2.2 隨機抽20個key,清理20個key中的已過期項
2.3 如果清理的過期項>25%(即:>=5個),則繼續上一步,隨機抽下一批20個.
聽上去比較合理,但是實際項目中,如果過期的key都是大key(即:占用內存很大),比例又在25%以下,又很少讀取(即:被動清理、主動清理,都可能干不掉它),它們占用的內存釋放會很慢,redis集群容量較少的情況下,隨着key的不斷寫入,可能會把內存用完。
如何監控這種情況?可以用redis-rdb-tools 解析redis的rdb文件,會生成一個csv文件,里面會列出所有key的基本信息(包括key數據結構類型,大小,過期時間等)
將expiry列做下排序,如果發現該列的值,比當前時間還早,說明過期了,但是還沒被清理。
有一個簡單的解決辦法:寫一個job,定期在業務低谷時段(比如:每天凌晨),把所有大Key訪問一遍即可。(即:強制觸發被動刪除,訪問的意思,並非一定要GET,使用TTL ,EXISTS命令都可以)