前置问题
- Q1、设置的 key 明明已经过期了,为啥 仍然占用内存?
- Q2、设置的 key 明明还没有过期,为啥 这个 key 就不见了?
这两个问题,通过 Redis 内存回收机制能够得到完美的解答。
Redis 内存回收机制
Redis 在两种情况下会回收 key 占用的内存:
- 用户主动设置过期时间,时间到了,被回收
- redis 中key达到了 redis 设置的 max_memory ,内存溢出。Redis 通过 LRU 算法进行Redis 内存回收。
1、删除达到过期时间的键对象
> 在 Redis 进程内保存了大量用户存入的 key ,针对设置了过期时间的 key ,如果每一个 key 进行精准的控制-当key过期立即回收空间,对于单线程的Reids来说成本太高。所以 Redis 中的 key 过期了,占用的内存空间并不会马上被回收, Redis 采用了两种方式:惰性删除和定时任务删除 来进行空间回收
-
惰性删除
当客户端进行某个 key 的get 访问,该key被设置了过期时间,如果此时 get 操作的时候 key 过期了,此时 Redis 将会针对该 key 占用的空间进行回收。
优点:该方式采用用户访问的方式进行空间回收,无需维护 key 的 TTL 链表数据。
缺点:如果存在大量已过期的 key 但是长时间内用户一直没有进行 get 方法,会导致过期 key 堆积在内存中,产生内存泄漏。
-
定时任务删除
Redis 内部维护一个定时任务,每秒执行10次。定时随机的进行过期key的内存回收。
运维知识:
> 定时任务删除,每秒执行次数 在 redis.conf 中 hz 进行配置,默认 hz 10
2、内存使用达到 max memory 上限时触发内存溢出控制策略
Redis 是一个缓存中间件,使用的内存空间,Redis 可以通过配置每个 Redis 实例的内存上限,或者 载体机器的内存上限。
在 Redis 的最大内存达到上限的时候,需要进行内存回收,或者拒绝写等策略来保证 Redis 正常提供服务。Redis 支持6种策略:
- noeviction:默认策略,不会删除任何数据,拒绝所有写入操作并返回客户端错误信息(error)OOM command not allowed when used memory,此时Redis只响应读操作。
- volatile-lru:根据LRU算法删除设置了超时属性(expire)的键,直到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction策略。
- allkeys-lru:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。
- allkeys-random:随机删除所有键,直到腾出足够空间为止。
- volatile-random:随机删除过期键,直到腾出足够空间为止。
- volatile-ttl:根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略。
运维知识
> 内存溢出控制策略 在 redis.conf 中 maxmemory-policy 进行配置,默认: maxmemory-policy noeviction > > 建议1:策略使用 volatile-lru 。保证服务正常提供的前提下,优先删除不常用的待过期的 key 。 > 建议2:频繁的策略回收会导致 Redis 性能下降设置阻塞,所以在设置 maxmemory 时,评估系统需要多大内存的 Redis 提供服务,尽量确保使用的内存 < max memory。 > 建议3:能够 通过 confg 命令进行动态配置策略。如:confg set maxmeory-policy {policy}
问题解答
Q1、设置的 key 明明已经过期了,为啥 仍然占用内存?
> 过期 key 需要通过 惰性删除 或者 定时任务删除,才会真正的被回收。
Q2、设置的 key 明明还没有过期,为啥 这个 key 就不见了?
> Redis max memory 达到上限。刚好设置策略为 非noeviction ,即使 key 未过期 仍然存在被回收的可能。 > > 反之,如果当 Redis 明明没有挂掉,但是总是写操作失败,就得看看报错信息,看看 max memory ,对比 内存使用量,加上 max memory 策略来判定,是否设置了 noeviction 策略,导致的问题。
更多精彩,关注公众号:【WTF名字好难取】!