Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,db数组中每个项都是一个redis.h/redisDb结构,每个redisDb结构代表一个数据库,默认redis服务器会创建16个数据库。
数据库键空间
Redis是一个键值对数据库服务器,服务器中每个数据库都由一个redis.h/redisDb结构表示,其中,redisDb结构的dict字典保存了数据库中的所有键值对,我们将这个字典成为键空间。
- 键空间的键也就是数据库的键,每个键都是一个字符串。
- 键空间的值也就是数据库的值,每个值可以是字符串对象、列表对象、哈希表对象、集合对象和有序集合对象中的任意一种Redis对象。
添加键:添加一个新键值对到数据库,其实就是将一个新键值对添加到键空间的字典里面,其中键为字符串对象,而值则为任意一种类型的Redis对象。
删除键:删除数据库中的一个键,实际上就是在键空间里面删除键所对应的键值对对象。
更新键:对一个数据库键进行更新,实际上就是对键空间里面键所对应的值对象进行更新,根据值对象的类型不同,更新的具体方法也会不同。
读写键空间:
当使用redis命令对数据库进行读写时,服务器不仅会对键空间执行指定的读写操作,还会执行一些额外的维护操作:
- 在读取一个键之后(读操作和写操作都要对键进行读取),服务器会根据键是否存在来更新服务器的键空间命中(hit)次数或键空间不命中(miss)次数。
- 读取一个键之后,服务器会更新键的LRU(最后一次使用)时间,这个值可以计算键的闲置时间。
- 如果服务器在读取时发现键已经过期了,服务器会先删除这个键,然后在执行其他操作。
- 如果客户端使用WATCH命令监视某个键,那么服务器在对被监视的键进行修改后,会将这个键标记为脏(dirty),从而让事务程序注意到这个键已经被修改。
- 服务器每次修改一个键之后,都会对脏(dirty)键计数器的值增1,这个计数器会触发服务器的持久化以及复制操作。
- 如果服务器开启了数据库通知功能,那么在对键进行修改之后,服务器将按排脂发送相应的数据库通知。
数据库设置生存时间或者过期时间
Redis的客户端可以通过EXPIRE或者PEXPIRE命令设置某个键的生存时间。(精度可以是秒或者毫秒)经过指定的时间后,服务器就会自动删除程村时间为0的键
过期时间其实是一个UNIX时间戳,当键过期时间来临时,服务器就会自动从数据库中删除这个键。
设置过期时间
由于Redis设置的过期时间是一个Unix时间戳,所以无论使用哪种命令设置过期时间,结果都是一样的。
- EXPIRE:设置key的生存时间为t秒
- PEXPIRE:设置key的生存时间为t毫秒
- EXPIREAT:设置key的过期时间为timestamp所指定的秒数时间戳
- PEXPIREAT:设置key的过期时间为timestamp所指定的毫秒数时间戳
使用过程都是将其他命令转换成PEXPIREAT命令进行设置过期毫秒级别时间戳。
保存过期时间
redisDb结构的expires字典保存了数据库中所有键的过期水岸,我们称这个字典为过期字典:
- 过期字典的键是一个指针,这个指针指向键空间的某个键对象
- 过期字典的值是一个long类型的整数,这个整数保存了键所指向的数据库键的过期时间,一个毫秒级别的UNIX时间戳。
一个键的过期时间可以通过PERSIST命令移除。也可以通过TTL命令以秒为单位返回键的剩余生存时间,而PTTL命令则返回的是毫秒级别的剩余生存时间。
过期键的判定
通过过期字典,程序可以用以下步骤检查给定一个键是否过期:
- 检查给定键是否存在于过期字典里,如果存在,那么取得键的过期时间
- 检查当前时间戳是否大于键的过期时间,如果是的话,那说明键已经过期,否则键未过期
过期键删除策略
- 定时删除:在设置键的过期时间的同时,创建一个定时器,将定时器在键的过期时间来临时,立即执行对键的删除操作。
- 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期就删除,如果没过期就返回该键。
- 定期删除:每隔一段时间,程序对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,由算法决定
定时删除
最友好的策略,通过定时器删除可以保证过期键会尽可能快的被删除,释放过期键所占的内存。缺点是对CPU的水岸不是最友好的,如果过期键比较多,删除的定时器就会一直占用CPU线程。
惰性删除
惰性删除对CPU时间是最友好的,但是对内存不友好,如果一个键过期,但是没有获取过,那么就会一直留在内存中无法释放。
定期删除
定期删除是前两种删除策略的折中:
- 定期删除策略没隔一段时间执行一次删除过期键操作,并通过闲置删除操作执行的市场和频率来减少操作对CPU时间的影响。
- 通过定期删除,有效的减少了因为过期键而打来的内存浪费。