Redis数据的过期与淘汰
懒惰处理
Redis在get操作时遇到过期的key会进行删除操作。
集中处理
Redis会将设置了过期时间的key放到一个独立的字典里,默认每秒10次过期扫描。扫描方式:
为防止扫描时间过长,扫描时间限制为25ms,开发时应尽量避免大量key同时过期。
从库不会进行过期扫描,主库删除时,会在AOF文件里增加一条del指令,同步到所有从库,从库通过此指令来删除。由于指令的同步存在异步,所以会出现主从数据不一致的情况。
当Redis内存超出物理内存限制时,内存数据会开始和磁盘产生频繁的交换,使得性能急剧下降。为了限制内存的使用,Redis提供参数 maxmemory 来限制最大内存,当内存超出后,会有以下策略( maxmemory-policy )来淘汰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内存数据里删除,将删除操作封装成一个任务丢到一个异步队列里。然后有个异步线程会从这个队列里取出任务并执行。
清空操作 flushdb 和 flushall ,在Redis4.0后,在指令后面增加 async ,就也可以像上面一样异步执行。
《Redis深度历险:核心原理和应用实践》