redis 数据库结构、RDB备份和AOF备份

数据库结构

redis的数据库是一个保存在redis服务器redisService结构体中的redisDb数组,redis客户端redisClient通过一个redisDb指针指向服务器内数据库数组内的一个元素。

键空间 字典

redisDb内部,是由一个字典组成,这个字典叫做键空间(key space)。所有对数据库的增删改查,都是对redisDb内字典的操作,字典的键总是字符串对象,字典的值可以是redis的五种对象的任意一种。

过期字典

除了保存所有数据的字典之外,redis维护过期键值对会使用一个过期字典,过期字典内保存的是键–过期时间(long long 类型时间戳,单位ms)的键值对。
过期键的处理策略包括:懒删除和定期删除,懒删除即只有当要访问指定键值对的时候,才查询该键值对是否过期;定期删除是指,指定一个时间间隔,每经过一个时间间隔则从过期字典中选出一部分键值对,判断是否过期。

设置键的过期时间有四种命令,底层都是使用的一种命令PEXPIREAT实现的:
* PEXPIREAT key timestamp: 指定键在某个时间戳之后过期,单位是ms
* EXPIRE key timestamp:指定键在某个时间戳之后过期,单位s,底层使用PEXIREAT实现
* PEXPIRE key ttl:指定键在ttl时间后过期,单位ms,底层使用PEXPIREAT计算后实现
* EXPIRE key ttl:指定键在ttl时间后过期,单位s,底层使用PEXPIRE实现

redis备份和复制机制中过期键值对的行为

  • RDB备份:备份时,过期键不会加入备份文件;还原文件时,如果还原到主服务器,过期键不会还原到内存,如果还原到从服务器,则还原到内存,之后通过于主服务器同步数据,来判断过期
  • AOF备份:以AOF持久化模式运行redis时,过期键的删除操作会产生一条删除记录到AOF文件,过期键本身会备份到文件;而当进行AOF重写的时候,过期键不会保存到重写后的AOF文件中
  • 复制:以复制模式运行redis时,过期键的删除由主服务器说了算,主服务器删除过期键的时候会给从服务器发送删除命令。也就是说如果从服务器没有接到删除命令,而有请求向从服务器读过期键,从服务器会返回对应的数据而不是返回过期错误。

RDB持久化

RDB持久化的保存

手动持久化

redis可以使用命令SAVE阻塞式的保存数据库数据,或者使用BGSAVEfork子进程保存数据库数据,BGSAVE不会使数据库阻塞
在redis服务器阻塞的时候,客户端的所有命令都会拒绝,当使用BGSAVE的时候,redis会对SAVEBGSAVE拒绝,而对BGREWRITEAOF命令延迟到BGSAVE命令执行结束后。对其他的命令正常执行。

自动持久化

可以设置redis服务器自动使用BGSAVE命令持久化。
redisService的结构体内有saveparam的结构体数组:

struct saveparam{
    time_t seconds;//秒数,表示一段时间内
    int changes;//修改数,表示seconds这段时间内需要满足的修改次数
}

当使用命令save seconds changes时,就会向saveparam数组内存储一个元素,表示如果在seconds秒内,数据库进行了至少changes次修改,则使用BGSAVE持久化一次数据库,save seconds changes命令可以运行多次,会产生多个条件
为了满足记录修改数,自动持久化的要求,redisService结构体内还有另外两个字段dirtylastsave来表明距离上一次成功执行SAVE命令或者BGSAVE命令的时间,和距那个时间以来的修改次数。
redis的周期函数serverCron会默认每隔100ms执行一次,这个函数的职责之一就是检测saveparam的条件是否满足,如果满足就执行BGSAVE
最后,redisServer关于定期保存的结构如下:

struct redisServer{
    // 和自动保存相关的属性
    long long dirty;//距上一次执行持久化以来数据库的修改次数
    time_t lastsave;//上一次持久化的时间,时间戳,单位s
    struct saveparam *saveparam;//自动保存的条件
}

RDB持久化的恢复

恢复是自动的,redis服务器在启动时自动检测RDB文件,发现即会使用,并且在恢复过程中阻塞,拒绝其他命令。

RDB文件的格式

RDB文件是二进制文件,包含四部分数据:
* REDIS字符串:5字节,表明这是个RDB文件
* db_version字段:4字节,表明RDB文件的版本
* databases:数据库内容,保存所有非空数据库内容
* EOF:1字节,文件结束符
* check_sum:8字节,无符号整数,校验和

databases结构:

  • SELECTDB:1字节,表明一个数据库的开始
  • db-number:1字节,2字节或者5字节,一个数据库的编号
  • key-value_pairs:数据库的键值对,如果有过期时间,则也包含在其中

key_value_paires结构:

  • EXPIRETIME_MS:1字节,常量,当存在过期时间时才有的标志位
  • ms:8字节,带符号整型,过期时间戳,如果没有过期时间,则没有该字段
  • TYPE:1字节,表明value类型的字段
  • key:总是字符串对象
  • value:值,各种对象
    关于各种对象如何持久化以及如何反持久化,见书P128,在此不记录

AOF持久化

AOF持久化的实现:命令追加、文件写入、文件同步

命令追加

redisServer结构体内有一个sds的缓冲区,新的写命令在执行之后,会将命令内容追加到这个缓冲区中

文件写入与同步

redis服务器使用一个事件循环处理文件事件和时间事件,文件事件诸如客户端的请求和响应的返回,时间事件诸如定时任务
AOF文件的写入是在每一次事件循环之后,写入到文件并判断是否要同步。有alaway,everysec,no三个同步选项。 默认位everysec,即每秒同步一次AOF文件

AOF文件的载入

redis服务器将会模拟客户端,执行一遍AOF文件内的所有命令,因为redis命令只能在客户端上下文运行, 所以redis服务器会创建一个没有网络连接的伪客户端。

AOF文件重写

  • AOF记录每一条写命令,随着时间变化,这个AOF文件会越来越大,为了减少AOF文件的体积,使用AOF重写。
  • 原理是将旧AOF文件对键值对的多条写命令改为 对键的一条写操作,这并不需要对旧的AOF文件的读取分析,而只需对数据库当前的键值对读,然后写文件即可完成。
  • 另外,如果是对列表,哈希表等包含多个键值对的集合操作的话,为了防止写操作造成缓存区溢出,AOF重写会将一次写改为多次写。
  • AOF重写会造成当前线程阻塞,所以redis将AOF重写操作放到子进程来做。
  • 重写完成后,子进程会向父进程发送信号量,父进程原子性的用新文件将旧文件覆盖掉。

AOF文件重写的不一致问题

可能在重写过程中,数据库存入了新的键值,但这不会记入重写的文件中
解决方法是:当在子进程使用AOF重写函数的时候,redis服务器设置了一个AOF重写缓冲区,每个写命令,不仅发送给AOF缓冲区,还发送给AOF重写缓冲区。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值