Redis数据库实现

目录

服务器中的数据库

切换数据库

数据库键空间

添加新键

删除键

更新键

对键取值

其他键空间操作

读写键空间时的维护操作

设置键的生存时间或过期时间

设置过期时间

保存过期时间

移除过期时间

计算并返回剩余生存时间

过期键的判定

过期键删除策略

定时删除

惰性删除

定期删除

Redis的过期键删除策略

 惰性删除策略的实现

定期删除策略的实现

Redis 内存淘汰机制

LRU 算法

LFU 算法

AOF、RDB和复制功能对过期键的处理

生成RDB文件

载入RDB文件

AOF文件写入

AOF重写

复制

数据库通知

发送通知

发送通知的实现

重点回顾


服务器中的数据库

Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db 数组中,db数组的每个项都是一个redis.h/redisDb结构,每个redisDb结构代表一 个数据库:

在初始化服务器时,程序会根据服务器状态的dbnum属性来决定应该创建多少个数据库:

dbnum属性的值由服务器配置的database选项决定,默认情况下,该选项的值为 16, 所以Redis服务器默认会创建16个数据库,如图

切换数据库

每个Redis客户端都有自己的目标数据库,每当客户端执行数据库写命令或者数据库读 命令的时候,目标数据库就会成为这些命令的操作对象。

默认情况下,Redis客户端的目标数据库为0号数据库,但客户端可以通过执行 SELECT命令来切换目标数据库。

以下代码示例演示了客户端在0号数据库设置并读取键msg, 之后切换到2号数据库 并执行类似操作的过程:

在服务器内部,客户端状态redisClient结构的db属性记录了客户端当前的目标数 据库,这个属性是一个指向redisDb结构的指针

redisClient.db指针指向redisServer.db数组的其中一个元素,而被指向的元 素就是客户端的目标数据库。

比如说,如果某个客户端的目标数据库为1号数据库,那么这个客户端所对应的客户端 状态和服务器状态之间的关系如图

如果这时客户端执行命令SELECT 2, 将目标数据库改为2号数据库,那么客户端状态 和服务器状态之间的关系将更新成图。

通过修改redisClient.db指针,让它指向服务器中的不同数据库,从而实现切换目 标数据库的功能一这就是SELECT命令的实现原理。

如果你在其他语言的客户端中执行Redis命令,并且该客户端没有像redis-cli那 样一直显示目标数据库的号码,那么在数次切换数据库之后,你很可能会忘记自己当前 正在使用的是哪个数据库。当出现这种情况时,为了避免对数据库进行误操作,在执 行Redis命令特别是像FLUSHDB这样的危险命令之前,最好先执行一个SELECT命令, 显式地切换到指定的数据库,然后才执行别的命令。

数据库键空间

Redis是一个键值对(key-value pair)数据库服务器,服务器中的每个数据库都由 一个redis.h/redisDb结构表示,其中,redisDb结构的dict字典保存了数据库中的 所有键值对,我们将这个字典称为键空间(key space) :

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

键空间的键也就是数据库的键,每个键都是一个字符串对象。

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

举个例子,如果我们在空白的数据库中执行以下命令:

那么在这些命令执行之后,数据库的键空间将会是图所展示的样子:

alphabet是一个列表键,键的名字是一个包含字符串"alphabet"的字符串对 象,键的值则是一个包含三个元素的列表对象。

book是一个哈希表键,键的名字是一个包含字符串"book"的字符串对象,键的 值则是一个包含三个键值对的哈希表对象。

message是一个字符串键.键的名字是一个包含字符串"message"的字符串对象, 键的值则是一个包含字符串"hello world"的字符串对象。

因为数据库的键空间是一个字典,所以所有针对数据库的操作,比如添加一个键值对到 数据库,或者从数据库中删除一个键值对,又或者在数据库中获取某个键值对等,实际上都 是通过对键空间字典进行操作来实现的,以下几个小节将分别介绍数据库的添加、删除、更 新、取值等操作的实现原理。

添加新键

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

举个例子,如果键空间当前的状态如图所示,那么在执行以下命令之后:

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

删除键

删除数据库中的一个键,实际上就是在键空间里面删除键所对应的键值对对象。 举个例子,如果键空间当前的状态如图所示,那么在执行以下命令之后:

键book以及它的值将从键空间中被删除,如图

更新键

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

举个例子,如果键空间当前的状态如图所示,那么在执行以下命令之后

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

如果我们继续执行以下命令

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

对键取值

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

举个例子,如果键空间当前的状态如图所示,那么当执行以下命令时:

GET命令将首先在键空间中查找键message, 找到键之后接着取得该键所对应的字符串对 象值,之后再返回值对象所包含的字符串"hello world", 取值过程如图

当执行以下命令时

LRANGE命令将首先在键空间中查找键alphabet,找到键之后接着取得该键所对应的列 表对象值,之后再返回列表对象中包含的三个字符串对象的值,取值过程如图

其他键空间操作

除了上面列出的添加、删除、更新、取值操作之外,还有很多针对数据库本身的Redis 命令,也是通过对键空间进行处理来完成的。

比如说,用于清空整个数据库的FLUSHDB命令,就是通过删除键空间中的所有键值对 来实现的。又比如说,用于随机返回数据库中某个键的RANDOMKEY命令,就是通过在键 空间中随机返回一个键来实现的。

另外,用于返回数据库键数量的DBSIZE命令,就是通过返回键空间中包含的键值对的 数量来实现的。类似的命令还有EXISTS、RENA.Me、KEYS等,这些命令都是通过对键空间 进行操作来实现的。

读写键空间时的维护操作

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

在读取一个键之后(读操作和写操作都要对键进行读取),服务器会根据键是否存在 来更新服务器的键空间命中(hit)次数或键空间不命中(miss)次数,这两个值可 以在INFO stats命令的keyspace_hits属性和keyspace_misses属性中查看。

在读取一个键之后,服务器会更新键的LRU (最后一次使用)时间,这个值可以用于 计算键的闲置时间,使用OBJECT idletime <key>命令可以查看键key的闲置时间。

如果服务器在读取一个键时发现该键已经过期,那么服务器会先删除这个过期键,然后才执行余下的其他操作。

如果有客户端使用WATCH命令监视了某个键,那么服务器在对被监视的键进行修 改之后,会将这个键标记为脏(dirty), 从而让事务程序注意到这个键已经被修改 过。

服务器每次修改一个键之后,都会对脏(dirty)键计数器的值增1这个计数器会触 发服务器的持久化以及复制操作。

如果服务器开启了数据库通知功能,那么在对键进行修改之后,服务器将按配置发 送相应的数据库通知。

设置键的生存时间或过期时间

通过EXPIRE命令或者PEXPIRE命令,客户端可以以秒或者毫秒精度为数据库中的某 个键设置生存时间(Time To Live, TTL), 在经过指定的秒数或者毫秒数之后,服务器就会 自动删除生存时间为0的键:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值