Redis—数据库

Redis数据库

1.服务器中的数据库

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

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

struct redisServer {
    //...
    //一个数组, 保存着服务器中的所有数据库
    redisDb *db;
    
    //...
    //服务器数据库数量
    intdbnum;
    //...
};

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

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

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

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

typedef struct redisClient {
    //...
    // 记录客户端当前正在使用的数据库
    redisDb *db;
    //...
} redisClient;

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

2.数据库键空间

Redis是一个键值对数据库服务器, 服务器中每一个数据库都由redis.h/redisDb结构表示, 其中, redisDb结构的dict字典保存了数据库中所有键值对, 我们把这个字典叫做键空间.

typedef struct redisDb {
    //...
    //数据库键空间, 保存着数据库中的所有键值对
    dict *dict;
    //...
} redisDb;

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

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

因为数据库的键空间是一个字典, 所以所有针对数据库的操作, 比如添加一个键值对到数据库, 或者从数据库中删除一个键值对, 又或者在数据库中获取某个键值对等, 都是通过对键空间字典进行操作实现的

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

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

类似的, 客户端可以通过EXPIREAT命令或PEXPIREAT命令, 以秒或者毫秒精度给数据库中的某个键设置过期时间

过期时间是一个UNIX时间戳, 当键的过期时间来临时, 服务器就会自动从数据库删除这个键

1>设置过期时间

实际上, 上面的EXPIRE, PEXPIRE, EXPIREAT, PEXPIREAT四个命令都是通过PEXPIREAT实现的, 即: 计算出过期时间的毫秒时间戳, 作为键过期时间

2>保存过期时间

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

  • 过期时间的键是一个指针, 这个指针指向键空间中的某个键对象(某个数据库键)
  • 过期时间的值是一个long long类型的整数, 这个整数保存了键所指向的数据库键的过期时间–一个毫秒精度的UNIX时间戳
3>移除过期时间

PERSIST命令可以移除一个键的过期时间, PERSIST命令就是PEXPIREAT命令, PERSIST命令在过期字典中查找给定的键, 并解除键和值(过期时间) 在过期字典中的关联

4>过期时间判定

通过过期字典, 程序可以用以下步骤检查一个给定键是否过期 :

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

4.过期键删除策略

如果一个键过期了, 有三种可能的策略来实现对过期键的删除

  • 定时删除 : 在设置键的过期时间的同时, 创建一个定时器(timer), 让定时器在键的过期时间来临时, 立即执行对键的删除操作
  • 惰性删除 : 放任过期键不管, 但是每次从键空间中获取键时, 都检查取得的键是否过期, 如果过期的话, 就删除该键; 如果没有过期, 就返回该键
  • 定期删除 : 每隔一段时间, 程序就对数据库进行一次检查, 删除里面的过期键.

这三种策略中, 第一种和第三种是主动删除策略, 第二种是被动删除策略

1>定时删除

定时删除是对内存友好的策略 : 通过使用定时器, 定时删除策略可以保证过期键会尽可能快地被删除, 并释放过期键所占用的内存

另一方面, 定时删除的缺点是 : 它对CPU是不友好的, 在过期键比较多的情况下, 删除过期键这一行为可能会占用相当一部分CPU. 会对服务器的响应时间和吞吐量造成影响

因此要让服务器创建大量的定时器, 从而实现定时删除策略, 并不现实

2>惰性删除

惰性删除策略是对CPU有好的 : 程序只会在取出键时才会对键进行过期检查, 这样可以保证删除过期键的操作只会在非做不可的情况下才会进行.

但它的缺点是对内存不友好 :如果一个键已经过期, 而这个键又还在内存中, 只要不读取这个键, 那么这个键就永远不会被删除, 可能会造成内存泄露

3>定期删除

对上面两种删除策略来看, 这两种删除方式在单一使用时都会有明显的缺陷

  • 定时删除占用的CPU时间太多, 影响服务器的响应时间和吞吐量
  • 惰性删除浪费太多内存, 有内存泄露的风险

定期删除是前两种策略的一种折中

  • 定期删除策略每隔一段时间执行一次删除过期键操作, 并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响
  • 除此之外, 通过定期删除过期键, 定期删除策略有效地减少了因为过期键而带来的内存浪费

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

5.Redis的过期键删除策略

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

1>惰性删除的实现

所有读写数据库的Redis命令在执行之前都会调用expireIfNeeded函数对输入键进行检查 :

  • 如果输入键已经过期, 那么expireIfNeeded函数将输入键从数据库删除

  • 如果输入键未过期, 那么exoireIfNeeded函数不做动作

因此, 每个命令都要能处理键存在以及键不存在这两种情况

  • 当键存在时, 命令按照键存在的情况执行
  • 当键不存在时或者因为过期而被expireIfNeeded函数删除时, 命令按照键不存在的情况执行
2>定期删除策略的实现

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

6.AOF, RDB和复制功能对过期键的处理

1>RDB

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

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

  • 如果服务器以主服务器模式运行, 那么在载入RDB文件时, 程序会对文件中保存的键进行检查, 未过期的键会被载入到数据库中, 而过期键则会被忽略, 所以过期键对载入RDB文件的主服务器不会造成影响
  • 如果服务器以从服务器模式运行, 那么在载入RDB文件时, 文件中保存的所有键, 不论是否过期, 都会被载入到数据库中. 因为在主从服务器在进行同步的时候, 从服务器的数据库就会被清空
2>AOF

当服务器以AOF模式运行时, 如果数据库中的某个键已经过期, 但它还没有被惰性删除或者定期删除, 那么AOF文件不会因为这个过期键而产生任何影响

当过期键被惰性删除或者定期删除后, 程序会向AOF文件追加(append)一条DEL命令, 来显式地记录该键已经被删除

在执行AOF重写的时候, 程序会对数据库中的键进行检查, 已过期的键不会被保存到重写后的AOF文件中

3>复制

当服务器运行在复制模式下时, 从服务器的过期键删除动作由主服务器控制 :

  • 主服务器在删除一个过期键之后, 会显示地向所有从服务器发送一个DEL命令, 告知从服务器删除这个过期键
  • 从服务器在执行客户端发送的读命令时, 即使碰到过期键也不将过期键删除, 而继续像处理未过期键一样处理过期键
  • 从服务器只有在接到主服务器发来的DEL之后才会删除过期键

通过由主服器来控制从服务器统一的删除过期键, 可以保证从服务器数据的一致性, 也正是因为这个原因, 当一个过期间仍然存在于主服务器的数据库时, 这个过期键在从服务器里的复制品也会继续存在

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值