redis的过期策略和内存淘汰
之前经常将将 Redis 的过期策略和内存淘汰策略搞混淆,查阅了一些资料后做个总结。
过期策略
Redis 所有的 key 都可以设置过期时间,时间一到就回自动删除。
如何设置过期时间
常用的方式有:
- EXPIRE key seconds
- EXPIREAT key timestamp
字符串独有的方式:
- SET key value [expiration EX seconds|PX milliseconds][nx|xx]
- SETEX key seconds value
Redis 采用的过期策略
惰性删除
- 在进行 get 或 setnx 等操作时,先检查 key 是否过期,
- 若过期,删除 key,然后执行相应操作;
- 若没过期,直接执行相应操作
定期删除
依次遍历每个数据库,默认每秒进行十次过期扫描- 检查当前库中的随机 20 个 key
- 删除这 20 个 key 中已经过期的 key;
- 如果过期的 key 比率超过 1/4,那就重复步骤 1
为了保证过期扫描不会出现循环过度,导致线程卡死现象,会判断定期删除操作是否已经达到指定时长(默认不会超过 25ms),若已经达到,直接退出定期删除。
如果某一个时间段,缓存集中过期失效,对于数据库而言,就会产生周期性的压力波峰造成缓存雪崩。如果有大批量的 key 过期,要给过期时间设置一个随机范围,而不宜全部在同一时间过期,分散过期处理的压力。
内存淘汰机制
用于缓存的内存不足时,Redis 提供了几种可选策略 (maxmemory-policy) 来让用户自己决定该如何腾出新的空间以继续提供读写服务。
noeviction 不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。
volatile-lru 尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。
volatile-ttl 跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。
volatile-random 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。
allkeys-lru 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。
allkeys-random 跟上面一样,不过淘汰的策略是随机的 key。
如果你只是拿 Redis 做缓存,那应该使用 allkeys-xxx,客户端写缓存时不必携带过期时间。
如果你还想同时使用 Redis 的持久化功能,那就使用 volatile-xxx 策略,这样可以保留没有设置过期时间的 key,它们是永久的 key 不会被 LRU 算法淘汰。
小结
Redis 采用惰性删除和定期删除,处理过期的缓存数据。
Redis 的内存淘汰策略的选取并不会影响过期的 key 的处理,用于处理内存不足时的需要申请额外空间的数据。