Redis数据的过期与淘汰

一、过期策略

懒惰处理
Redis在get操作时遇到过期的key会进行删除操作。

集中处理
Redis会将设置了过期时间的key放到一个独立的字典里,默认每秒10次过期扫描。扫描方式:

  1. 从过期字典里随机选20个key;
  2. 删除这20个key里已经过期的;
  3. 如果过期的key比率超过1/4,那么重复步骤1;

为防止扫描时间过长,扫描时间限制为25ms,开发时应尽量避免大量key同时过期。
从库不会进行过期扫描,主库删除时,会在AOF文件里增加一条del指令,同步到所有从库,从库通过此指令来删除。由于指令的同步存在异步,所以会出现主从数据不一致的情况。

二、内存溢出淘汰

当Redis内存超出物理内存限制时,内存数据会开始和磁盘产生频繁的交换,使得性能急剧下降。为了限制内存的使用,Redis提供参数maxmemory来限制最大内存,当内存超出后,会有以下策略(maxmemory-policy)来淘汰key以腾出空间:

  • noeviction(默认) 不让写,只让读。
  • volatile-lru LRU的方式淘汰设置了过期时间的key。
  • volatile-ttl 淘汰ttl最小的设置了过期的key
  • volatile-random 随机淘汰设置了过期时间的key
  • allkeys-lru LRU的方式淘汰所有key中的一个
  • allkeys-random 随机淘汰所有key中的一个

由于LRU算法需要消耗大量的额外内存,redis采用一种近似的LRU算法。它给每个 key 增加了一个额外的小字段(24bit),也就是最后一次被访问的时间戳。每次执行写操作时,如果发现内存超出maxmemory,就随机采样5个(参数maxmemory_samples配置)key,然后淘汰最旧的。如果淘汰之后还是超出,那就继续随机淘汰,直到不超出为止。如果maxmemory-policy是volatile-xxx,就从设置过期时间的key里采样,否则就从所有key里采样。
Redis3.0里增加了一个淘汰池,就是一个大小为maxmemory_samples的数组。每次淘汰时会将随机出来的key和数组里的key融合,淘汰掉最旧的一个,然后将剩下的较旧的key放到淘汰池里给下个循环用。

三、惰性删除

redis的删除del在删除一个大对象的时候有可能造成卡顿。为了解决这个问题Redis4.0引入了unlink指令,将这个key的对象引用从Redis内存数据里删除,将删除操作封装成一个任务丢到一个异步队列里。然后有个异步线程会从这个队列里取出任务并执行。
清空操作flushdbflushall,在Redis4.0后,在指令后面增加async,就也可以像上面一样异步执行。

参考资料

《Redis深度历险:核心原理和应用实践》

你可能感兴趣的:(Redis数据的过期与淘汰)