Redis的内存回收机制主要体现在两个方面:
- 通过删除到达过期时间的键对象,释放内存空间
- 内存使用到达maxmemory上限时触发内存溢出控制策略(Redis技术查漏补缺(一)-淘汰策略)
1 删除过期键对象
过期删除策略大体可以分为三种:惰性删除、定期删除、定时删除
1.1 惰性删除
放任键过期不管, 但是每次从键空间中获取键时, 都检查取得的键是否过期, 如果过期的话, 就删除该键; 如果没有过期, 就返回该键。
惰性删除策略不对过期键进行处理,此时因为内存没有达到Redis的maxmemory上限而没触发淘汰策略,Redis只会在访问键的时候进行过期检查,当键超过过期时间即会执行删除并返回空。惰性删除的缺点就是对内存不友好,会使已过期的内存内存长期占有内存空间。
1.2 定期删除
在《Redis开发与运维》中对过期删除策略使用了惰性删除和定时任务删除来总结过期删除策略,但是通过我对《Redis设计与实现》、Redis核心技术与实战极客专栏等资料阅读普遍把在默认时间内进行删除操作的策略定名为定期删除策略
每隔一段时间, 程序就进行一次检查, 删除里面的过期键。 至于要删除多少过期键, 以及要检查多少个数据库, 则由算法决定。
Redis的定期删除策略内部维护一个定期任务,Redis 每隔一段时间(默认100ms),就会随机选出一定数量键(ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP是Redis的一个参数,默认是 20)的数据,检查它们是否过期,并把其中过期的键删除。定期删除会因为触发机制导致Redis性能下降。
1.3 定时删除
在1.2小节我们对定时删除还是定期删除做了我个人的定义,我们以《Redis设计与实现》对定时删除来定义来说明,在设置键的过期时间的同时,每一个过期键创建一个定时器,当定时器到达定时时后立刻删除改键。如果在一定时间内过期键过多那么过多的定时器会对CPU造成负担,因为有这样的问题所以没有给讲求高效的Redis所使用。
2 不同情况下的惰性删除
如果 Redis 开启了持久化和主从同步,那么 Redis 的过期处理要复杂⼀些。
2.1 持久化
在生成RDB文件的时候,程序会的数据库中的键进行检查,已过期的键不会被保存到新创建的RDB文件。
当服务器以AOF持久化模式运行时,如果Redis中的某个键已经过期,但它还没有被惰性删除或者定期删除,那么AOF文件不会因为这个过期键产生任何影响。当触发惰性删除或者定期删除之后,程序会向AOF追加一条DEL命令,来显式记录该键已被删除。
在执行AOF重写的时候会对内容进行检查,已过期的键不会被保存到重写后的AOF文件中。
2.2 主从同步
主从同步之下,从服务器等待主服务器的删除命令
如果 Redis 开启了主从同步,那么从库对过期键的处理,不同版本有不同策略。对于实际生产使用来说,我推荐Redis升级到3.2以后的版本,因为从库都是等主库的删除命令,但是对于读来说:
如果你使用的是 Redis 3.2 之前的版本,那么,从库在服务读请求时,并不会判断数据是否过期,而是会返回过期数据。
在 3.2 版本后,Redis 做了改进,如果读取的数据已经过期了,从库虽然不会删除,但是会返回空值,这就避免了客户端读到过期数据。
3 定期删除带来的问题
定期删除在各版本的实现细节上有所不同,但是总结下来就是当随机抽取的键数组超过25%过期的情况下,会循环执行删除操作,又因Redis是单线程进行命令执行的,因此会较大的影响Redis的性能。
出现这种情况常见引起原因是有数量较多的带有相同过期时间的键,导致一次定期删除内有大量的键过期。
鉴于上面所述的情况,我们已知定期删除的频率是毫秒级别的,因此当我们需要对大量键在同一时间进行过期的时候,我们可以对这些键过期时间毫秒位加入一定的随机数,我们即可以保证数据在秒内过期,同时又不会造成在一次定期删除内过多的删除键导致影响Redis的性能。
书籍:《Redis开发与运维》