Redis设计 - RDB持久化

前言

Redis 是内存数据库,它将数据存储在内存里,如果不想办法将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所以 Redis 提供了持久化功能。

本章将带你了解Redis持久化的RDB持久化是如何实现的。

RDB 持久化概述

  • RDB 持久化既可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个 RDB 文件中。
  • RDB 持久化功能所生成的 RDB 文件是一个经过压缩的二进制文件,通过该文件可以还原生成 RDB 文件时的数据库状态。


    RDB持久化、还原

RDB 文件的创建与载入

创建

有两个Redis命令可以生成RDB文件,一个是SAVE,另一个是BGSAVE:
SAVE 命令会阻塞 Redis 服务器进程,直到 RDB 文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求。
BGSAVE 命令会派生出一个子进程,然后由子进程负责创建 RDB 文件,父进程继续处理命令请求。

SAVE 命令执行时的服务器状态
当save命令执行时,Redis服务器会被阻塞,所以当save命令正在执行时,客户端发送的所有命令请求都会被拒绝。

BGSAVE命令执行
BGSAVE命令保存的工作由子进程执行,所以在子进程创建RDB的过程中,Redis服务器仍然可以继续处理客户端命令请求,但是在BGSAVE命令执行期间,服务器处理SAVE、BGSAVE、BGREWRITEAOF 三个命令的方式会和平时有所不同:

  • SAVE命令会被拒绝,避免父进程和子进程同时调用rdbSave方法,防止产生竞争条件。
  • BGSAVE命令会被拒绝,也会产生竞争条件。
  • BGWRITEAOF命令和BGSAVE命令不能同时执行:
    1.BGSAVE正在执行时,BGREWRITEAOF命令会被挂起,直到BGSAVE命令执行完毕后执行。
    2.BGREWRITEAOF正在执行,BGSAVE命令直接被拒绝。

载入

RDB 文件的载入工作是在服务启动时自动执行的,所以 Redis 并没有专门用于载入 RDB 文件的命令,只要 Redis 服务器在启动时检测到 RDB 文件存在,它就会自动载入 RDB 文件。

因为 AOF 文件的更新频率通常比 RDB 文件的更新频率高,所以如果服务器开启了 AOF 持久化功能,那么服务器会优先使用 AOF 文件来还原数据库状态,只有在 AOF 持久化功能处于关闭状态时,服务器才会使用 RDB 文件来还原数据库状态。

服务器载入持久化文件流程

自动间隔保存

因为BGSAVE命令可以在不阻塞服务器的情况下执行,所以redis允许用户通过设置服务器的save选项,让服务器每隔一段时间自动执行BGSAVE命令。

通过save选项可设置多个保存触发条件,任意一条满足,就会执行BGSAVE命令,例如:

save 900 1 // 900秒内,对数据库至少1次修改
save 300 10 // 300秒内,对数据库至少10次修改
save 60 10000 // 60秒内,对数据库至少10000次修改

其实xx秒内,对数据库修改xx次就触发保存是不准确的,正确的理解应该是至少满足过了xx秒,且修改次数超过xx次

如果没有主动配置save选项,上面的配置就是默认条件

dirty计数器和lastsave属性

除了保存条件外,服务器还保存着一个dirty计数器和最后保存时间,用于判断是否满足自动保存的条件。

  • dirty 计数器记录距离上一次成功执行 SAVE 命令或者 BGSAVE 命令之后,服务器对数据库状态进行了多少次修改(包括写入、删除、更新等操作)。
  • lastsave 属性是一个 UNIX 时间戳,记录了服务器上一次成功执行 SAVE 命令或者 BGSAVE 命令的时间。
检查保存条件是否满足

Redis 的服务器周期性操作函数 serverCron 默认每隔 100 毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,它的其中一项工作就是检查 save 选项所设置的保存条件是否已经满足,如果满足的话,就执行 BGSAVE 命令。

那么serverCron函数是如何判断是否满足条件的?这就需要用到save选项的配置、dirty计数器和lastsave属性来判断了,伪代码如下所示:

def serverCron() {
    # ...
    # 遍历所有保存条件
    for saveparam in server.saveparams:
        # 计算距离上次执行保存操作有多少秒
        save_interval = unixtime_now() - server.lastsave
        # 如果数据库状态的修改次数超过条件所设置的次数
        # 并且距离上次保存的时间超过条件所设置的时间
        # 那么执行保存操作
        if server.dirty >= saveparam.changes and save_interval > saveparam.seconds:
            BGSAVE()
        # ... 
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容