对于Redis服务器来说,内存资源非常宝贵,如果一些过期键一直不被删除,就会造成资源浪费,因此我们需要考虑当一个键过期了,它需要被删除。惰性删除策略,是redis可选的删除策略之一。
数据删除场景
涉及到数据删除的场景有很多,盘点有如下场景:
场景一:客户端执行的显示删除/清除命令,比如 del,flushdb 等;
场景二:某些指令带有的隐式删除命令,比如 move , rename 等;
场景三:到达过期时间的数据需要删除;
场景四:使用内存达到 maxmemory 后被选出来要淘汰的数据需要删除;
场景五:在主从同步全量同步阶段,从库收到主库的 RDB 文件后要先删除现有的数据再加载 RDB 文件;
在 redis 4.0 以后,redis 新增了异步删除的功能 : lazy free,也叫 惰性删除,它可以 将 “数据删除” 放到后台线程中去执行,进而避免对主线程的阻塞。
惰性删除介绍
放任过期键不管,每次从键空间中获取键时,检查该键是否过期,如果过期,就删除该键,如果没有过期,就返回该键。
惰性删除策略只会在获取键时才对键进行过期检查,不会在删除其它无关的过期键花费过多的CPU时间。
因此,惰性删除策略的优缺点如下所示:
优点:
删除操作只发生在通过key取值的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)
缺点:
若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)
举个例子,如果数据库有很多的过期键,而这些过期键又恰好一直没有被访问到,那这些过期键就会一直占用着宝贵的内存资源,造成资源浪费
惰性删除策略的实现
过期键的惰性删除策略由expireIfNeeded函数实现,所有读写数据库的Redis命令在执行之前都会调用expireIfNeeded函数对输入键进行检查:
- 如果输入键已经过期,那么将输入键从数据库中删除
- 如果输入键未过期,那么不做任何处理
以上描述可以使用如下流程图表示:
惰性删除配置
redis 提供了对应的配置项来控制对应场景下是否启用惰性删除:
- lazyfree-lazy-user-del / lazyfree_lazy_user_flush (0 新增): 显示删除/清除命令场景;
- lazyfree-lazy-eviction:是否异步驱逐 key,当内存达到上限,分配失败后
- lazyfree-lazy-expire:是否异步进行 key 过期事件的处理
- lazyfree-lazy-server-del:del 命令是否异步执行删除操作,类似 unlink
- replica-lazy-flush:replica client 做全同步的时候,是否异步 flush 本地 db
以上参数默认都是 no,按需开启