Redis设计与实现之数据库键空间

什么是数据库键空间

redis是一个键值对数据库服务器, 服务器中每一个数据库都由一个 server.h/redisDb 的结构表示, 其中, redisDb 结构中的 dict字典 保存了数据库中所有的键值对, 这个字典即位键空间(keyspace)

键空间和用户所见的数据库是直接对应的

  • 键空间的键也就是数据库的键, 每个键都是一个字符串对象
  • 键空间的值也就是数据库的值, 每个值可以是字符串对象、列表对象、哈希表对象、集合对象、有序集合对象中的任意一种Redis对象

举例, 假如我们在一个空白的数据库中依次执行以下命令

键空间存储数据示例

上述指令执行完成之后, 数据库的键空间如下图所示:

数据库键空间存储状态

添加新键

添加一个新键到数据库, 实际上就是讲一个新键值对添加到键空间字典里面, 其中键为字符串对象, 而值为任意一种类型的Redis对象。

举例,如果数据库空间如上图(图9-4)所示, 那么在执行以下命令后

1
2
redis> set date "2013.12.1"
OK

键空间将新增加一个键值对, 这个新键值对的键是一个包含字符串 “date” 的字符串对象, 而键值则是一个包含字符串 “2013.12.1” 的字符串对象, 如下图

添加date键之后的键空间

删除键

删除数据库中的一个键, 实际上就是在键空间里面删除一个键值对所对应的对象

举例, 加入初始键空间如图9-4所示, 那么执行以下命令:

1
2
redis> del book
(integer) 1

键book以及它的值将会从键空间被删除, 如下图所示:

删除book键之后的键空间

更新键

对一个数据库的键更新, 实际上就是对监控里面键空间里面键所对应的值对象进行更新, 根据值对象类型的不同, 更新的具体方法也会有所不同.

举例, 键空间依旧如 9-4 所示, 那么执行以下命令

1
2
redis> set message "blah blah"
OK

键message的值对象, 将会从之前包含 “hello world” 字符串 更新为包含 “blah blah” 的字符串, 如下图所示

使用set命令更新message键

在上述结果的基础之上, 继续执行如下命令

1
2
redis> hset book page 320
(integer) 1

那么键空间中, book键的值对象(一个哈希对象)将会被更新, 新的键值对 page 和 320 键会被添加到 值对象里面, 如下图所示:

使用hset更新book键

对键取值

对于一个数据库键进行取值, 实际上就是在键空间中, 取出键所对应的值对象, 根据值对象的类型不同, 具体的取值方法也会有所区别.

如果当前键空间如图 9-4 所示, 执行以下命令:

1
2
redis> get message
"hello world"

get命令将首先在键空间中查找键message, 找到键之后, 取得该键所对应的字符串对象值, 之后在返回值对象所包含的字符串 “hello world” , 取值过程如下:

使用get命令取值过程

如果继续执行如下命令:

1
2
3
4
redis> lrange alphabet 0 -1
1) "a"
2) "b"
3) "c"

lrange 命令将首先在键空间中查找键 alphabet, 找到键之后, 取出键所对应的列表对象值, 之后在返回列表所包含的三个字符串对象值, 取值过程如下图:

使用lrange命令取值过程

其他键空间操作

除了基础的添加、删除、更新、取值之外, 还有很多针对数据库本身的redis命令, 也是通过对键空间进行处理完成的.

如: 清空整个数据库的命令 flushdb, 就是通过删除键空间中所有键值对实现的

如: 随机返回数据库中某个键的 randomkey 命令, 就是通过在键空间中随机返回一个键来实现的.

如: 用户返回数据库键数量的 dbsize 命令, 通过返回键空间中键值对的数量来实现

类似的命令还有: exists、reanme、keys等

读写键空间时的维护操作

当使用Redis命令对数据库进行读写时, 服务器不仅会对键空间执行指定的读写操作, 还会执行一些额外的维护操作.

  • 在读取一个键之后(读操作和写操作都要对键进行读取), 服务器会根据键是否存在, 更新服务器键空间中的命中(hit)次数或者未命中(miss)次数, 即对应 info stats 中的 keyspace_keys 与 keyspace_misses
  • 读取一个键之后, 服务器会更新键的LRU(最后一次使用时间), 这个值可以用于计算key的闲置时间, 可使用 object idletime <key> 来获取.
  • 如果服务器在读取一个键时, 发现该键已过期, 服务器会先删除这个过期的键, 再执行余下的其他操作
  • 如果有客户端使用 watch 监控了某个键, 那么服务器在对被监视的键进行修改之后, 会将这个键标记为脏(dirty), 从而让十五程序注意到这个键已经被修改过.
  • 服务器每次修改一个键之后, 都会对脏(dirty)键计数器加1, 这个计数器会出发服务器的持久化以及复制操作.
  • 如果开启了数据库通知功能, 那么在对键进行修改之后, 服务器将会按照配置发送相应的数据库通知.

参考资料


Redis设计与实现之数据库键空间
http://www.zhangdeman.cn/archives/825363d7.html
作者
白茶清欢
发布于
2021年12月6日
许可协议