redis.h文件中 redisServer结构包含一个db数组
db数组中的每一项都是一个redis.h文件中的 redisDb结构,每个redisDb就是一个数据库
-
redisServer中的dbnum决定了数据库的数量,默认为16个
image.png
切换数据库
- 每个redis客户端都有自己对应的目标数据库
- 默认都选择0号数据库,但是可以通过执行select命令来切换,比如select 2就是选择2号数据库
-
redisClient结构的db属性记录了当前客户端的目标数据库,该属性是指向redisDb结构的指针
image.png
数据库键空间
- 我们成一个db中的dict字典为键空间。
-
键空间和用户所见的数据库是直接对应的
image.png
- 如下图分别展示了键值是list hashtable,string的三种形态
-
整个db 就是一个dict(A),A中的key是我们常写的key 其职能是字符串对象,value 则可以是五种对象
image.png
读写键空间时的维护操作
- 当我们对DB进行读写操作时候还会进行一些额外的操作
- 在读取一个键之后(读写操作都需要读取键),服务器会根据键是否存在来更新服务器键空间命中(hit)次数和不命中(miss)次数,我们分别可以在keyspace_hits和keyspace_misses查看
- 在读取一个键之后,服务器会更新键的LRU,该值用来计算键的空闲时间
- 在读取一个键之后,如果发现该键已经过期,那么服务器会先删除这个过期键,然后才执行余下的其他操作。
- 如果有客户端使用了watch命名监视某个键,那么服务器对监视的键进行修改后会将这个键标记为脏(dirty),从而让食物程序注意到这个键已经被修改过
- 每次修改一个键之后,都会对dirty键计数器自增1,这个计数器会触发服务器的持久化和赋值操作
- 如果服务器开启了数据库通知功能,那么对键进行修改后,服务器将会按照配置发送相应的数据库通知
设置键的生存时间或过期时间
- expire或者pexpire 都可以以秒或者毫秒为精度为某个键设置生存时间(TIME TO LIVE TTL),服务器会在指定时间自动删除生存时间为0的键
- setex 可以设置一个字符串键的同时设置一个过期时间,但是其只限于字符串键(对于其他的list或者hash等不适合)
expire(生存时间,秒) pexpire(生存时间毫秒) expireat (过期时间 ,秒)pexpireat(过期时间,毫秒数) 都可以设置键的生存时间(键可以存在多久)或者过期时间(什么时候删除)
- 过期时间都是 保存的unix的时间戳,而生存时间都是保存的秒数或者毫秒数
上面前三个指令都是依赖pexpireat实现的

redisDb结构的expires字典保存了数据库中所有键的过期时间,我们称呼这个为过期字典
- 过期字典的键是一个指针,这个指针指向键空间中的某个键对象(即指向key)
- 过期字典的值是一个 long long 类型的整数,这个整数保存了键所指向的数据库键的过期时间--毫秒精度的unix时间戳


-
TTL命令可以秒为单位返回键的剩余生成时间,PTTL则以毫秒返回,主要原理就是去过期字典获取过期时间然后减去当前时间
-
persist 命令可以移除一个键的过期时间,该命令在过期字典中查找给定的键,并删除该key和valvue
-
redis 检测过期键的步骤如下:检测key是否存在过期字典中,检测所要查找的key的时间戳与当前时间进行对比
过期键删除策略
-
定时删除:对内存最友好,通过定时器,定时删除,减少内存占用策略,但是对于cpu不好(因为线程总是要占用cpu执行),造成吞吐量和响应时间不高。创建一个定时器需要用到redis服务器中的时间事件(类似我们一个socket事件),那么每个键都需要一个定时器,导致时间事件以无序列表存储,查找一个事件的时间复杂度N,这就导致效率不高。
-
惰性删除:对于cpu最好(使用该key才检测是否过期),但是对于内存不友好。如果我们不使用该key 可能存在内存泄漏
-
定期删除:定期执行一次删除过期键的操作,但是频率和时长需要考虑,不能太频繁 也不能太低
-
redis 使用惰性删除和定期删除
-
惰性删除依靠expireIfNeeded函数实现,读写数据库前都需要调用该函数,如果键过期就删除否则不做处理。

- 定期删除策略通过activeExpireCycle函数实现,每次redis的服务器周期性操作serverCron函数,而serverCron则调用activeExpireCycle,其主要是在规定时间内分多次遍历服务器中的各个数据库,从数据库中的expire字典中随机检查一部分键的过期时间,并删除

RDB 对过期键进行处理
- 生成RDB:已经过期的键不会被保存到RDB文件
- 载入RDB: 如果服务器是主服务器,则在载入RDB文件时候,对于已经过期的键会忽略,而若是从服务器则不会忽略,但是因为主从服务器在进行数据同步,从服务器的数据库就会被情况
AOF对过期键进行处理
- AOF文件写入: 如果是以AOF的形式运行,但是该键就算过期但是没有被删除,还是会写入文件,如果被删除后AOF 会在文件中追加一条DEL命令,来显示记录该键删除
- AOF 重写: 程序会对数据库文件中的key进行检查,已经过期的不会被保存到重写后的AOF文件
复制
- 当处于复制模式,从服务器的过期键删除动作由主服务器控制
- 主服务器删除一个过期键,会显示低向从服务器发送一个DEL命令
- 从服务器遇到读命令,读到过期键也不会删除
- 从服务器收到主服务器DEL命令才删除过期键
- 这样的好处可以保持主从数据的一致性(比如从服务检测到过期键删除,而主服务器没有检测到,那么主从就不一致了)
通知分为 键空间通知和键事件通知,前者可以监控一个key执行了哪些命令,后者可以监控一个命令被哪些键执行了
网友评论