按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命令都可以)