过期字典
redisDb 结构的 expires 字典保存了数据库中所有键的过期时间,我们称这个字典为过期字典。
- 过期字典的键是一个指针,该指针指向键空间里面的某个键对象
- 过期字典的值是一个 long long 类型的整数,这个整数保存了键指向的数据库键的过期时间(毫秒精度的Unix时间戳)。
过期键的认定
is_expired函数(Redis 实际使用,直接访问字典比执行命令稍快一点)
- 检查给定键是否存在于过期字典里面,如果存在,则取出过期时间;
- 判断Unix当前时间戳是否大于过期时间,如果大于,则键值已经过期,否则,键值未过期。
TTL 命令
- 如果对某个键执行 TTL 命令,如果返回值大于等于 0 ,表示该键不过期!
过期策略
- 定时删除:在设置键的过期时间时,同时创建一个定时器,让定时器在键的过期时间来临时,立即进行删除。
- 惰性删除:放任键过期不管,在每次取键时,检查是否过期,如果过期,删除键值,否则返回键值。
- 定期删除:每隔一段时间,程序对数据库做一次检查,删除里面的过期键;每次扫描多少个数据库,每个数据库删除多少个键值,都可以通过配置文件搞定。
以上的第一种和第三种为主动删除策略,第二种为被动删除策略。
过期策略优缺点
定时删除
- 优点:对内存是最友好的,定时删除策略使用定时器,可以尽可能快的删除键值,释放键值的内存占用
- 缺点:对 CPU 时间最不友好,在过期键过多的情况下,会大量占用CPU时间,在内存不紧张CPU时间紧张的情况下,将CPU时间浪费在过期键的删除中,会影响服务器的吞吐量和响应时间;而且创建定时器需要用到Redis的时间事件,而Redis的时间事件是一个无序链表,查找一个时间事件的复杂度为0(N),并不能高效的处理大量时间事件。
惰性删除
- 优点:对CPU时间最友好,只会在取出该键时对键值进行检查,不会因为删除无关的键值,占用CPU时间
- 缺点:对内存最不友好,一个键值过期了,但是它仍然保留在数据库中,那么它一直不被删除,内存就一直不会被释放。比如一些和时间相关的数据:日志。
定期删除
- 优点:是定时删除和惰性删除的折中方式,通过控制删除操作的执行频率和执行时间,减少对CPU时间的占用,同时定期的删除过期键,减少了内存浪费。
- 缺点:难以确定删除操作的执行时长和频率。
Redis 使用的删除策略
Redis 的过期策略是惰性删除和定期删除两种策略结合来使用的。
惰性删除
Redis 的惰性删除是由 db.c/expireIfNeeded 函数实现的,所有读写Redis数据库的命令在执行前,都会执行该函数检查输入键。如果输入键过期,expireIfNeeded 函数删除键;如果输入键没有过期,expireIfNeeded 函数不做任何操作。
定期删除
Redis 的定期删除是由 redis.c/activeExpireCycle 函数实现的,每当 Redis 服务器上 redis.c/serverCorn 函数执行时,activeExpireCycle 函数都会被调用,它在规定的时间内,分多次遍历服务器上的多个数据库,从数据库的 expire 字典中随机检查一部分键的过期时间,看是否过期,如果过期,就删除。
每次检查的数据库数量,每次从数据库取出的键值数量,都可以通过配置文件进行配置。
通过全局变量 current_db ,记录当前执行到哪个数据库,如果数据库被遍历一遍后,current_db 会被重置为 0,从头开始计数。
过期键对AOF、RDB持久化和复制的影响
1. 生成 RDB 文件
在执行 SAVE 或BGSAVE 命令创建一个新的 RDB 文件时,会对数据库中的键进行检查,已过期的键不会被记录到 新的 RDB 文件中。
2. 载入 RDB 文件
- 如果服务器以主服务器的模式运行,那么在载入 RDB 文件时,程序会对RDB 文件中的键进行检查,未过期的键导入到数据库中,已过期的键,则会被忽略,所以不会影响。
- 如果服务器以从服务器的模式运行,那么在载入 RDB 文件时,不论键是否过期,都会导入到数据库,但是主从服务器在进行数据同步时,从服务器的数据会被清空,所以一般情况下, 过期键也不会影响到 Redis 的从服务器。
3. AOF 文件写入
过期键对 AOF 文件写入不会有任何影响。当过期键被惰性删除或定期删除时,会往 AOF 文件中追加一条 DEL 命令,显式的记录该条记录被删除。
4. AOF 文件重写
执行 AOF 文件重写时,程序会对AOF 文件中的键进行检查,已过期的键不会被保存到新的 AOF 文件中去,所以不会影响。
5. 复制
服务器在复制模式下,服务器的过期键删除由主服务器控制。
- 主服务器在删除一个过期键之后,会显式的发送一条 DEL 命令给所有的从服务器,告知从服务器删除这个过期键。
- 从服务器在执行客户端发来的读命令时,即使碰到过期键也不会删除,而是继续像处理未过期键一样,处理过期键。
- 从服务器只会在接收到主服务器发送的 DEL 命令,才会删除过期键。