一起学习Redis | 聊聊Redis的数据过期删除策略?




  • 前提概要
  • 删除?
  • 数据过期删除策略
  • 定时删除
  • 惰性删除
  • 相关问题
  • 所以假如一个Redis实例中的海量key在同一时间过期了,会出现什么样的结果呢?
  • 有时候使用dbsize查询出来的数量,比实际的数据量要多一些?

前提概要


删除?

Redis的所有数据本质上就是存储在一个巨型字典里。我们可以对该字典的所有key设置一个过期时间,时间一到,该key及对应的数据就会被自动删除。所以你可以简单的想象成,Redis内部有一个地府衙门,黑白无常时刻的盯着设置了过期时间的数据,检查它们的寿命还剩多少,一旦发现寿命到期,就将其带走!

cmd中redis清空指定数据库 redis清空db_cmd中redis清空指定数据库


同时,毕竟黑白无常就那么两个人,如果有一天,有大量的数据同时寿命到期,黑白无常会不会忙不过来?也就是说,Redis是一个单线程模型的进程,删除数据本身也占据一定的时间,会不会因为大量的删除操作而阻塞了正常的业务操作呢?

这个当然会呀,但是在了解结果之前,我们要先来了解一下Redis的数据过期删除策略



数据过期删除策略


定时删除

什么是定期删除?

  • 定期删除又称集中删除,主动删除。既Redis会给每个设置了过期时间的Key放到一个独立的字典中。我们成为过期数据字典。以后Redis会定时的遍历这个字典的所有Key, 统一检查数据寿命,只要发现过期数据就会立即删除
  • Redis默认每秒进行10次的过期扫描,既每100ms就扫描一次。但这些过期扫描并不会遍历整个过期数据字典, 而是采用一种贪心策略的方式,每次只扫描一部分
  • 为什么是抽检而不是整体呢?如果你有10w的过期键,如果你对整体进行遍历查询,时间复杂度是O(n), 这么这一次遍历,单线程的Redis就会被你这个操作直接卡顿,其他的业务操作也不用做了。

定期删除的贪心策略

  • 从过期数据字典中随机选出20个key
  • 删除这20个key中已经过期的key
  • 如果过期的key的比例超过了1/4, 那就重复步骤1
  • 同时为了保证过期扫描不会循环过度,导致线程卡死,算法还增加了扫描时间的最大上限,默认不超过25ms

惰性删除

那么什么是惰性删除呢?

  • 惰性删除也称为,零散删除,被动删除
  • 因为定期删除每次只会扫描一部分的过期数据字典,所以有可能会导致一部分的过期数据被遗留下来,没有得到及时删除。所以惰性删除就是作为一种定期删除不足的补救措施,当你在获取某个key的时候,Redis会先检查一下,如果该key设置了过期时间,并已经过期,那么Redis再会删除该数据。既用到时判断,过期就删除,这也就是为什么称为惰性删除
  • 只有key被操作时,Redis才会被动检查该key是否过期,如果过期则删除之并且返回nil。
  • 如果定时删除留下的过期key过多,而惰性删除又没有触发,此时内存告警,就会走内存淘汰策略

惰性删除的优缺点

  • 惰性删除,可以弥补定时删除留下的漏洞,保证过期数据不会被客户端使用到
  • 惰性删除对CPU是友好的,删除操作只有在不得不的情况下才会进行,不白白浪费宝贵的CPU资源。
  • 但是惰性删除会造成一定的无用数据的内存空间占用,既无用数据占用了宝贵的内存空间资源,等同浪费


相关问题


所以假如一个Redis实例中的海量key在同一时间过期了,会出现什么样的结果呢?
  • Redis会持续扫描过期字典,循环多次,知道过期字典中的过期的key占比降低,才会停止。这就导致线程读写请求出现明显的卡顿现象。
  • 当客户端有请求过来时,如果服务器正好进入过期扫描状态,那么客户端的请求将可能会等待25ms后,才能得到处理。会导致业务请求有明显的延时
  • 所以业务开发人员一定要注意过期时间,避免让同一时间出现大量的key过期。可以通过给过期实际一个随机数范围去避免
  • 其实这本质就是Redis的缓存雪崩危机,这里仅仅是从Redis本身的角度分析,如果缓存雪崩危机严重的话,很有可能会造成数据库的宕机,乃至系统的不可用!

有时候使用dbsize查询出来的数量,比实际的数据量要多一些?

有一个场景如下

  • 通过dbsize命令查询Redis有多少的数据量, 得到34578
  • 通过redis-cli keys * | wc -l查询Redis中实际的数据量,得到30015

为什么dbszie查到的数据量会比keys *得到的数据量要多呢?

  • 因为这是是redis对过期键处理机制导致的误差。 dbsize返回的是包含过期键的总数。而keys * 因为被动调用了过期的key,触发惰性删除,所以过期的key就查不到了。