八、数据库(redis)

一、服务器中的数据库

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

二、切换数据库

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

三、数据库键空间

Redis是一个键值对key-value pair)数据库服务器,服务器中的每个数据库都由 一个redis .h/redisDb结构表示,其中,redisDb结构的diet字典保存了数据库中的 所有键值对,我们将这个字典称为键空间(key space):
    键空间的键也就是数据库的键,每个键都是一个字符串对象
    键空间的值也就是数据库的值,每个值可以是字符串对象、列表对象、哈希表对象、 集合对象和有序集合对象中的任意一种Redis对象


添加新键
    SET date "2013.12.1"
删除键
    DEL book (integer) 1
更新键
     SET message "blah blah"
    HSET book page 320
对键取值
    GET message "hello world"

 

3.1 读写键空间时的维护操作

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

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

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

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

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

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

6.如果服务器开启了数据库通知功能,那么在对键进行修改之后,服务器将按配置发送相应的数据库通知,本章稍后讨论数据库通知功能的实现时会详细说明这一点。

 

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

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

客户端可以以秒或者毫秒精度为数据库中的某 个键设置生存时间

4.1保存过期时间

redisDb结构的expires字典保存了数据库中所有键的过期时间,我们称这个字典 为过期字典

过期字典的键是一个指针,这个指针指向键空间中的某个键对象

过期字典的值是一个long long类型的整数,这个整数保存了键所指向的数据库 键的过期时间,个毫秒精度的UNIX时间戳

4.2设置过期时间

   Expire<key><ttl>
        命令用于将键key的生存时间设置为ttl秒
    Pexpire<key><ttl>
        命令用于将键key的生存时间设置为ttl毫秒
    Expireat<key><timestamp>
        命令用于将键key的过期时间设置为timestamp所指定的秒数时间戳
    Pexpireat<key><timestamp>
        命令用于将键key的过期时间设置为timestamp 所指定的毫秒数时间戳


    其他三个命令最终都会转换成Pexpireat命令来执行

4.3移除过期时间

Persist命令可以移除一个键的过期时间
通过在过期字典中査找给定的 键,并解除键和值(过期时间)在过期字典中的关联


4.4 计算并返回剩余生存时间

    TTL <key>
        以秒为单位返回键的剩余生存时间
    PTTL <key>
        以毫秒为单位返回键的剩余生存时间


4.5 过期键的判定

检査给定键是否存在于过期字典:如果存在,那么取得键的过期时间
检查当前UNIX时间戳是否大于键的过期时间:如果是的话,那么键已经过期;否 则的话,键未过期

注意:

实现过期键判定的另一种方法是使用TTL命令或者PTTL命令,比如说,如果对某个键 执行TTL命令,并且命令返回的值大于等于0,那么说明该键未过期。在实际中,Redis检 查键是否过期的方法和is_expired函数所描述的方法一致,因为直接访问字典比执行一 个命令稍微快一些。

 

五、过期建的删除策略

5.1定时删除

在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的 过期时间来临时,立即执行对键的删除操作
    对内存是最友好的:
        通过使用定时器,定时删除策略可以保证过期键会尽 可能快地被删除,并释放过期键所占用的内存
    对CPU时间是最不友好的:
        在过期键比较多的 情况下,删除过期键这一行为可能会占用相当一部分CPU时间
        将CPU时间用在删除和当前任务无关的过期键上,无疑会对服务器 的响应时间和吞吐量造成影响

5.2惰性删除

放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否 过期,如果过期的话,就删除该键;如果没有过期,就返回该键
    对CPU时间最友好的:
        程序只会在取出键时才对键进行过期检査, 这可以保证删除过期键的操作只会在非做不可的情况下进行
    对内存是最不友好:
        如果一个键已经过期,而这个键又仍 然保留在数据库中,那么只要这个过期键不被删除,它所占用的内存就不会释放

 

5.2定期删除

 每隔一段时间,程序就对数据库进行一次检査,删除里面的过期键。至 于要删除多少过期键,以及要检査多少个数据库,则由算法决定。

从上面对定时删除和惰性删除的讨论来看,这两种删除方式在单一使用时都有明显的缺陷:

定时删除占用太多CPU时间,影响服务器的响应时间和吞吐量。

惰性删除浪费太多内存,有内存泄漏的危险。

定期删除策略是前两种策略的一种整合和折中:

定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的 时长和频率来减少删除操作对CPU时间的影响。

除此之外,通过定期删除过期键,定期删除策略有效地减少了因为过期键而带来的 内存浪费。

定期删除策略的难点是确定删除操作执行的时长和频率:

如果删除操作执行得太频繁,或者执行的时间太长,定期删除策略就会退化成定时 删除策略,以至于将CPU时间过多地消耗在删除过期键上面。

如果删除操作执行得太少,或者执行的时间太短,定期删除策略又会和惰性删除策 略一样,出现浪费内存的情况。

因此,如果采用定期删除策略的话,服务器必须根据情况,合理地设置删除操作的执行时长和执行频率。

 

六、Redis的过期键删除策略

Redis服 务器实际使用的是惰性删除和定期删除两种策略:通过配合使用这两种删除策略,服务器可以很好地在合理使用CPU时间和避免浪费内存空间之间取得平衡。

6.1 惰性删除策略的实现

过期键的惰性删除策略由db.c/expirelfNeeded函数实现,所有读写数据库的 Redis命令在执行之前都会调用expireIfNeeded函数对输人键进行检查:

1.如果输人键已经过期,那么expirelfNeeded函数将输人键从数据库中删除。

2.如果输人键未过期,那么expirelfNeeded函数不做动作。

因为每个被访问的键都可能因为过期而被expirelfNeeded函数删除,所以每 个命令的实现函数都必须能同时处理键存在以及键不存在这两种情况:

1.当键存在时,命令按照键存在的情况执行。

2.当键不存在或者键因为过期而被expirelfNeeded函数删除时,命令按照键不存 在的情况执行。

6.2定期删除策略的实现

过期键的定期删除策略由redis . c/activeExpireCycle函数实现,每当Redis的 服务器周期性操作redis . c/serverCron函数执行时,activeExpireCycle函数就会被调用,它在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expires字 典中随机检查一部分键的过期时间,并删除其中的过期键。

activeExpireCycle函数的工作模式可以总结如下:

1.函数每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查,并删 除其中的过期键。

2.全局变量current_db会记录当前activeExpireCycle函数检査的进度,并 在下一次activeExpireCycle函数调用时,接着上一次的进度进行处理。比如 说,如果当前activeExpireCycle函数在遍历10号数据库时返回了,那么下 次activeExpireCycle函数执行时,将从11号数据库开始査找并删除过期键。

3.随着activeExpireCycle函数的不断执行,服务器中的所有数据库都会被检 查一遍,这时函数将current_db变量重置为0,然后再次开始新一轮的检查 工作

 

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

7.1生成RDB文件

在执行SAVE命令或者BGSAVE命令时会创建一个新的RDB文件时,程序会对数据库中的 键进行检查,已过期的键不会被保存到新创建的RDB文件中

7.2载入RDB文件

在启动Redis服务器时,如果服务器开启了 RDB功能,那么服务器将对RDB文件进行载人

如果服务器以主服务器模式运行,那么在载人RDB文件时,程序会对文件中保存的 键进行检查,未过期的键会被载入到数据库中,而过期键则会被忽略,所以过期键 对载入RDB文件的主服务器不会造成影响。

如果服务器以从服务器模式运行,那么在载人RDB文件时,文件中保存的所有键, 不论是否过期,都会被载人到数据库中。不过,因为主从服务器在进行数据同步的 时候,从服务器的数据库就会被清空,所以一般来讲,过期键对载人RDB文件的从 服务器也不会造成影响。

7.3AOF文件写入

当服务器以AOF持久化模式运行时,如果数据库中的某个键已经过期,但它还没有被 惰性删除或者定期删除,那么AOF文件不会因为这个过期键而产生任何影响。
当过期键被惰性删除或者定期删除之后,程序会向AOF文件追加(append) —条DEL 命令,来显式地记录该键已被删除

7.4AOF 重写

和生成RDB文件时类似,在执行AOF重写的过程中,程序会对数据库中的键进行检 査,已过期的键不会被保存到重写后的AOF文件中

7.5 复制

当服务器运行在复制模式下时,从服务器的过期键删除动作由主服务器控制
        主服务器在删除一个过期键之后,会显式地向所有从服务器发送一个说命令,告 知从服务器删除这个过期键
        从服务器在执行客户端发送的读命令时,即使碰到过期键也不会将过期键删除,而 是继续像处理未过期的键一样来处理过期键
        从服务器只有在接到主服务器发来的命令之后,才会删除过期键

 

八、数据库通知

客户端通过订阅给定的频 道或者模式,来获知数据库中键的变化,以及数据库中命令的执行情况
服务器配置的notify-keyspace-events选项决定了服务器所发送通知的类型
    AKE
        服务器发送所有类型的键空间通知和键事件通知
    AK
        服务器发送所有类型的键空间通知
    AE
        服务器发送所有类型的键事件通知
    K$
        服务器只发送和字符串键有关的键空间通知
    El
        服务器只发送和列表键有关的键事件通知

8.1 发送通知实现

发送数据库通知的功能是由notify. c/notifyKeyspaceEvent函数实现的:

void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid);

notifyKeyspaceEvent函数执行以下操作:

1. server.notify_keyspace_events 属性就是服务器配置 notify-keyspace- events选项所设置的值,如果给定的通知类型type不是服务器允许发送的通知类型,那 么函数会直接返回,不做任何动作。

2.如果给定的通知是服务器允许发送的通知,那么下一步函数会检测服务器是否允许 发送键空间通知,如果允许的话,程序就会构建并发送事件通知。

3.最后,函数检测服务器是否允许发送键事件通知,如果允许的话,程序就会构建并 发送事件通知。

 

9、特点

数据库主要由diet和expires两个字典构成,其中diet字典负责保存键值对, 而expires字典则负责保存键的过期时间
因为数据库由字典构成,所以对数据库的操作都是建立在字典操作之上的
当一个过期键被删除之后,服务器会追加一条命令到现有AOF文件的末尾, 显式地删除过期键
当Redis命令对数据库进行修改之后,服务器会根据配置向客户端发送数据库通知。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值