redis.h/redisServer 结构的 db 数组中,每个元素都是 redis.h/redisDb 结构,代表一个数据库
初始化服务器时会根据服务器状态的 dbnum 属性来决定创建多少个数据库
dbnum 由服务器配置的 database 选项决定,默认为 16,所以会默认创建 16 个数据库
Redis 客户端的目标数据库为 0 号数据库,可以通过 SELECT 命令来切换目标数据库
127.0.0.1:6379> set 32 "hello you"
OK
127.0.0.1:6379> get 32
"hello you"
127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]> get 32
(nil)
127.0.0.1:6379[2]> set 32 "you hello"
OK
127.0.0.1:6379[2]> get 32
"you hello"
在服务器内部,客户端状态的 redisClient 结构的 db 属性记录了客户端当前的目标数据,是一个指向 redisDb 结构的指针
redisClint.db 指针指向 redisServer.db 数组的一个元素,被指向的元素则是客户端的目标数据库
redis 是键值对数据库服务器,每个数据库都是 redis.h/redisDb 结构表示,dict 字典保存了数据库中的键值对,这个字典为键空间
键空间与数据库是直接对应的
所有针对数据库的操作,实际上都是通过对键空间字典进行操作实现的
添加新键
添加新键值对到数据库,实际上就是将新键值对添加到键空间中,键为字符串对象,值为任意一种 Redis 对象
删除键、更新键、对键取值
同理添加新键
其他命令
FLUSHDB、RANDOMKEY、DESIZE 同样也是通过对键空间进行操作的
不仅只有指定的读写操作,还有一些额外的维护操作,包括
服务器会根据键是否存在来更新键空间命中次数和不命中次数,使用 INFO status 命令的 keyspace_hits 和 keyspace_misses 属性查看
服务器会更新键的 lru (最后一次使用)时间,可以计算键的闲置时间, OBJECT idletime key 查看
读取一个键时发现已经过期了,则会先删除再进行余下的操作
如果客户端使用 watch 命令监视了某个键,则服务器修改后,会将其标记为脏,从而让事务程序注意到键已经修改
每修改一个键后,脏键计数器的值 + 1,会触发服务器的持久化以及复制操作
如果服务器开启数据库通知功能,在对键进行修改之后,服务器会按配置发送相应的数据库通知
所有命令底层还是由 PEXPIRE 命令转换而来的
redisDb 结构的 expires 字典保存了数据库中所有键的过期时间,即过期字典:
键为指针,指向键空间的某个键对象
值为 long long 类型,保存了键指向的键空间键对象的过期时间,毫秒精度的 UNIX 时间戳
键空间和过期字典的键都指向同一个,此处为明显展示而列举两个
PERSTST 命令移除键的过期时间:
在过期字典中查找给定的键,并解除键和值在过期字典中的关联
TTL 秒为单位,PTTL 毫秒为单位,通过计算键的过期时间与当前时间之差
或者使用 TTL 或 PTTL 命令,但实际中是使用 is_expired 函数
内存友好
CPU 最不友好
需要使用 Redis 的时间事件,时间事件实现方式为无序链表,则查找一个事件的时间复杂度为 O(N)
对 CPU 最友好
对内存最不友好
浪费大量内存
每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响,有效减少了过期键的内存浪费
时长和频率难以确定:
执行频繁、时间长,会退化成定时删除
执行少、时间短,退化为惰性删除
由 db.c/expireIfNeeded 函数实现,所有读写数据库的 Redis 命令在执行之前都会调用此函数对输入键进行检查
命令执行时也需要按照两种情况执行
由 redis.c/activeExpireCycle 函数实现,Redis 周期性操作 redis.c/serverCron 函数执行时,activeExpireCycle 函数会调用,在规定时间内,分多次遍历各个数据库,从 expires 字典中随机检查一部分键的过期时间,并删除过期键
activeExpireCycle:
在执行 save 命令或者 bgsave 命令创建新的 RDB 文件时,对键会进行检查,已经过期的键不会被保存到新创建的 RDB 文件中
对 RDB 文件进行载入:
以主服务器模式运行,在载入时会对文件中保存的键进行检查,未过期的键会被载入到数据库中,已过期的会被忽略
以从服务器模式运行,文件中所有键都会被载入数据库,但是主从服务器进行数据同步时,从服务器的数据库就会被清空
服务器以 AOF 持久化模式运行时,如果某个键过期,但没有被惰性删除或者定期删除,AOF 文件不会因这个过期键产生任何影响
当过期键被删除后,会向 AOF 文件追加一条 DEL 命令显示记录该键已被删除
类似生成 RDB 文件,对键检查,已过期的不会被保存
当服务器在复制模式下,从服务器的过期删除动作由主服务器控制:
通过主服务器控制从服务器统一删除过期键,来保证主从服务器的一致性
让客户端通过订阅给定的频道或者模式,来获知数据库中键的变化,以及命令的执行情况
notify-keyspace-events 决定发送通知的类型
发送所有类型的键空间通知和键事件通知:AKE
发送所有类型的键空间通知:AK
发送所有类型的键事件通知:AE
发送和字符串键相关的键空间通知:K$
发送和列表键相关的键事件通知:EL
发送数据库通知功能由 notify.c/notifyKeyspaceEvent 实现:
void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid);
type 为当前想要发送的通知的类型,根据这个值来判断通知是否就是服务器配置 notify-keyspace-event 选项所选定的通知类型来决定是否发送通知
event 事件名称
keys 产生事件的键
dbid 产生事件的数据库号
根据这些参数来构建事件通知的内容、以及接受通知的频道名
REDIS_NOTIFY_SET:集合键通知
REDIS_NOTIFY_GENERIC:通用类型通知
notifyKeyspaceEvent:
pubsubPublishMessage 是PUBLISH 命令的实现函数
原文:https://www.cnblogs.com/zephxu/p/14915745.html