Redis的过期策略和内存淘汰策略
关于Redis过期时间的的几个常见问题
为什么要给Redis的key设置过期时间?
有时候我们并不希望redis的key一直存在。例如缓存,验证码等数据,我们希望它们能在一定时间内自动的被销毁。redis提供了一些命令,能够让我们对key设置过期时间,并且让key过期之后被自动删除
Redis的过期时间如何判定?
在Redis内部,每当我们设置一个键的过期时间时,Redis就会将该键带上过期时间存放到一个expires字典中。当我们查询一个键时,Redis便首先检查该键是否存在过期字典中,如果存在,那就获取其过期时间。然后将过期时间和当前系统时间进行比对,比系统时间大,那就没有过期;反之判定该键过期。
//每个数据库都是一个redisDb,id为数据库编号
typedef struct redisDb {
dict *dict; //键空间,保存了数据中所有键值对
dict *expires; //过期字典,保存了数据库中所有键的过期时间
dict *blocking_keys;
dict *ready_keys;
dict *watched_keys;
struct evictionPoolEntry *eviction_pool;
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
} redisDb;
如何设置Redis key的过期时间?
- EXPIRE key ttl :表示将键 key 的生存时间设置为 ttl 秒。
- PEXPIRE key ttl :表示将键 key 的生存时间设置为 ttl 毫秒。
- EXPIREAT key timestamp :表示将键 key 的生存时间设置为 timestamp 所指定的秒数时间戳。
- PEXPIREAT key timestamp :表示将键 key 的生存时间设置为 timestamp 所指定的毫秒数时间戳。
redis的过期策略
当Redis过期了之后,如果没有及时清除掉,这时候的过期的key实际上还是会占用内存,为了避免大量的过期key占用过高的系统内存,这时候就有了Redis的过期策略
目前Redis采用的策略:惰性删除+定期删除
基于时间的过期
每个键都可以设置一个过期时间,当键过期时,会被自动删除。在Redis中,使用EXPIRE key seconds命令来给键设置过期时间,使用TTL key命令来获取键的剩余时间。
这样的过期策略其实是不被建议的,尽管会让我们的内存保持key的有效性,让内存的空间利用率达到最大,但是这样频繁操作key的删除,势必会影响CPU,CPU压力较大,无论CPU此时负载情况如何,均会占用CPU来执行删除,会影响Redis服务器的响应时间和指令吞吐量。
惰性删除
当客户端尝试访问某个键时,Redis会检查该键是否已经过期,如果过期则会将其删除。这种策略虽然不会立即删除过期键,但是减少了Redis的主动清理工作,可以提高Redis的性能。
定期删除
Redis会每隔一段时间就对一定数量的键进行检查,删除其中过期的键。这种策略相比惰性删除更为主动,但需要消耗额外的CPU资源。
前面讲到每个redisDB 都对应了一个expires。那么这个定期删除策略就是随机抽取每个DB的expires中的W个key进行检测,具体步骤如下:
- Redis在启动的时候会读取配置文件hz里面的信息,默认为10,代表每秒执行10次serverCron()操作
- 在serverCron()中会调用databasesCron()来轮询每一个db(即循环expire[ * ])。
- 在databasesCron()中会调用activeExpireCycle()方法,对每一个expire[ * ]进行检测,每次执行的时长伟250ms/server.hz。
- 对某个expire[ * ]检测时,随机挑选W个key进行检测。如果key超时,即删除。
- 如果第四步中,删除的key的数量大于W*25%,则继续在此expire[ * ]上检测执行。
- 如果第四步中删除的key的数量小于等于W*25%,则检测下一个expire[ * ]。(从0-15循环,Redis默认为16个DB)
其中W值,可以在配置文件中配置,对应的属性为ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP;
在第四步中的activeExpireCycle()方法执行检测的时候,因为时间长度时固定的,下一次activeExpireCycle()方法执行为了接着上一次中断的位置执行,用参数current_db来记录当前检测的expire。
Redis的内存淘汰策略
每进行一次redis操作的时候,redis都会检测可用内存,判断是否要进行内存淘汰,当超过可用内存的时候,redids 就会使用对应淘汰策略
Redis如何设置内存数值量
- 我们可以通过配置文件修改,安装完redis之后我们可以在redis根目录中找到redis.conf文件,在配置文件中添加一下参数就可以设置redis的内存大小了
# 设置 Redis 最大使用内存大小为100M
maxmemory 100mb //指定最大内存为100mb
当 Redis 使用的内存超过 100Mb 时,就开始对数据进行淘汰。
- 通过命令设置
//设置Redis最大占用内存大小为100M
127.0.0.1:6379> config set maxmemory 100mb
//获取设置的Redis能使用的最大内存大小
127.0.0.1:6379> config get maxmemory
内存淘汰设置
1.no-envicition:
该策略对于写请求不再提供服务,会直接返回错误,当然排除del等特殊操作,redis默认是no-envicition策略。
2.allkeys-random:
从redis中随机选取key进行淘汰
3.allkeys-lru:
使用LRU(Least Recently Used,最近最少使用)算法,从redis中选取使用最少的key进行淘汰
4.volatile-random:
从redis中设置过过期时间的key,进行随机淘汰
5.volatile-ttl:
从redis中选取即将过期的key,进行淘汰
6.volatile-lru:
使用LRU(Least Recently Used,最近最少使用)算法,从redis中设置过过期时间的key中,选取最少使用的进行淘汰
7.volatile-lfu:
使用LFU(Least Frequently Used,最不经常使用),从设置了过期时间的键中选择某段时间之内使用频次最小的键值对清除掉
8.allkeys-lfu:
使用LFU(Least Frequently Used,最不经常使用),从所有的键中选择某段时间之内使用频次最少的键值对清除