Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,db数组中的每个项都是一个redis.h/redisDb结构,每个redisDb都表示着一个数据库:
在redisServer使用一个数组来保存数据库。
在初始化的时候会通过redisServer中的dbnum来决定创建多少个数据库。dbnum属性的值由服务器配置的database选项决定,默认情况下创建16个数据库。如下图所示
客户端可以通过SELECT命令来对数据库进切换。SELECT的逻辑就是改变指针的引用
在服务器内部是通过redisClient结构的db属性记录客户端当前目标的数据库。redisClient.db指针指向redisServier.db数组中的某一个元素。
Redis是一个键值对的数据库,思想是极致的节省内存,每个数据库都是redisDb数组中的一个,其中redisDb中的dict字典保存了数据库中的所有键值对。成为键空间。
但其实这肯定不符合redis的设计思想嘛,我这么多KV都放着了,肯定是不现实的,键空间对于用户选择的数据库是相对应的也就是你选择的是1号数据库那是只会存储1号数据库里面的所有KV。
当添加一个KV进入数据库的时候,Key是SDS,而Value可以是任何一个redisObject。如果是V是一个hashtable里面就还有有一个新的dict,ht[0],ht[1]什么的
删除的时候也是常规的思想,就是把这个KV从字典的引用中去除就行了。
更新的话根据不同的RedisObject会有不同的实现。
取值的操作也是一样的,先从redisDb对象里面的dict找到key,然后再从redisObjetct中去获取value。如果是hashtale 的情况可以自己思考下,应该很容易就可以想明白了
在读写键空间的时候也会有很多额外的操作
1.读取键的时候,会根据这个value是否存在,然后更新键空间中的hit 或者 miss变量。
2.读取一个键的时候,会更新这个redisObject中的lru变量,从而更新时间
3.如果读取的时候发现这个键值对已经无效了,那么就会先删除这个key然后进行余下的操作
4.如果这个value被watch了,在修改的时候就会对这个键标记为脏
5.如果修改了一个键之后,会对这个键进行计数加一。方便后续的事物程序进行管理
6.如果开启了通知,那么就会发送对应的通知消息
给Key设置存活时间,这个也是在平时开发中经常使用到的东西,通过EXPIRE或者PEXPIRE命令来进行实现,SETEX和PEXPIRE的逻辑是一样的。TTL以及PTTL是返回剩余的存活时间。
在redisDb结构中还包含了一个expires字典,也就是过期字典,用来存储已经过期的Key和过期的时间
至于如何进行删除,如果从资源分配的角度上思考,惰性删除是最好的,因为不用时时刻刻拉着一个线程进行。
可以说惰性+定时的组合是最好的,针对业务进行时间上的choose
最后就是AOF和RDB了这个也是面试中很经常问到,一定要耐心。
在执行SAVE或者BGSAVE的时候,程序会对数据库里面的键进行check,已经过期的Key不会被保存到新建的RDB文件中。
在启动Redis服务器的时候(主服务器模式),会读取RDB中的文件,这时候也会对RDB中的数据进行check如果已经过期了就不会载入到数据库中去。如果是正常的服务器模式就会都载入进去。
如果服务器是以AOF进行运行的。当Key被过期的时候,就会想AOF中追加一条DEL命令,这个也可以看出在读取AOF是根据时间的有序性进行读取的。
在主从服务器架构中,当主服务器知道了一个key过期的时候 会向从服务器也发送一个DEL消息,让从服务器也去删除Key
从服务器遇到自身带的过期key的时候也会正常执行,从服务器只会对主服务器给的DEL消息进行执行。所以如果主从情况下,主节点一定一定要对过去的key可靠保证的发送消息。
数据库通知是2.8之后的新功能 没啥意思
smartcat.994