Redis的持久化机制

RDB持久化

RDB持久化既可以手动,也可以配置,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中。

RDB文件是一个经过压缩的二进制文件,通过文件可以还原生成RDB文件时的数据库状态。

image

RDB文件的创建与载入

有2个命令可以生成RDB文件:SAVE和BGSAVE。SAVE命令会阻塞主进程,BGSAVE会派生子进程,由子进程创建

RDB文件。

redis> SAVE
OK

redis> BGSAVE
Background saving started

RDB文件的载入是在服务器启动时自动执行的,检测到RDB文件就会自动载入RDB文件。但是AOF文件的更新频率

通常比RDB文件的更新频率高,所以:开启了AOF,会优先使用AOF。

BGSAVE命令执行时的服务器状态

因为BGSAVE命令的保存工作是由子进程执行的,所以在子进程创建RDB文件的过程中,Redis服务器可以继续处

理客户端的命令请求。BGSAVE命令执行期间,服务器处理SAVE、BGSAVE、BGREWRITEAOF和平时不同。

  • BGSAVE执行期间,客户端发送的SAVE命令会被拒绝,因为同时执行父进程和子进程都会调用rdbSave,产生竞

争。两个BGSAVE命令也同理。

  • BGSAVE和BGREWRITEAOF不能同时执行:

    • 如果BGSAVE正在执行,客户端发送的BGREWRITEAOF会延迟到BGSAVE之后执行。
    • 如果BGREWRITEAOF正在执行,那么客户端发送的BGSAVE会被服务器拒绝。

    因为BGREWRITEAOF和BGSAVE都是由子进程执行,并且同时执行大量IO操作,不是好策略。

RDB文件载入时的服务器状态

服务器在载入RDB文件期间,会一直阻塞到完成。

自动间隔性保存

Redis允许用户通过设置save,让服务器每隔一段时间自动执行一次BGSAVE命令。

可以设置多个保存条件,只要任意条件被满足,服务器就会执行BGSAVE命令。

save 900 1 // 900s内至少1次修改就执行BGSAVE命令
save 300 10 // 300s内至少10次修改
save 60 10000 // 

检查保存条件是否满足

周期性操作函数serverCron默认每隔100毫秒会执行一次,检查save是否满足条件,满足就执行BGSAVE。

RDB文件结构

  1. RDB开头是五个字符“REDIS”,快速检查载入文件是否为RDB文件。

  2. db_version是RDB文件的版本号。

  3. databases包含零个或多个数据库。

  4. EOF表示正文内容结束。

  5. check_sum保存校验和,通过前四个字段计算得出,检查RDB文件是否有出错的情况出现。

image

例子:

redis> set MSG "HELLO"
redis> save

$ od -c dump.rdb
R E D I S 0 0 0 6 376 \0 \0 003 M S G 005 H E L L O 377 207 z = 304 f T L 343
// 377代表EOF

AOF持久化

AOF通过保存Redis执行的写命令来记录数据库状态。Redis的命令请求协议是纯文本格式,所以AOF文件是纯文本。

AOF持久化的实现

命令追加

AOF打开后,服务器执行一个写命令后,会将写命令追加到aof_buf缓冲区末尾。

AOF文件的写入与同步

Redis的进程是一个事件循环,这个循环中的文件事件负责接收客户端的命令请求,以及发送回复,而时间事件则执行定时运行的函数。

服务器在处理文件事件时可能会执行写命令,使得一些内容被追加到aof_buf缓冲区里面,所以在服务器每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区中的内容写入和保存到AOF文件里。flushAppendOnlyFile函数的行为由appendfsync来配置。

通过配置appendfsync可以决定缓冲区的内容什么时候放入AOF文件里,

  • 设置为always,每次write后都会调用fsync(Linux为调用fdatasync)。
  • 设置为everysec为最多每秒调用一次fsync,这种模式性能并不是很糟糕,因为所有fsync操作都异步交给了BIO线程。
  • 设置为no,write后不会有fsync调用,由操作系统自动调度刷磁盘,性能是最好的。

AOF文件的载入与数据还原

  1. 创建一个不带网的fake client。
  2. 从AOF文件中读取一条写命令。
  3. 直到读完。

AOF重写

随着时间流逝,AOF会越来越大,

image

记录这个list键的状态,AOF就要保存六条命令。

AOF文件重写的实现

如果服务器想尽量少的命令记录list键的状态,简单高效的方法就是!读取list的值,太聪明了!我宣布个事,六条

命令减少到了一条。

因为aof_rewrite函数生成的新AOF文件只包含还原当前数据库状态所必须的命令,所以新AOF文件不会浪费任何

硬盘空间。

AOF后台重写

aof_rewrite使用子进程解决主进程阻塞的问题,可是,如果新的命令可能会对数据库进行修改,从而造成当前状

态和重写后的AOF文件保存的数据库状态不一致。

为了解决这个问题,Redis服务器设置了一个AOF重写缓冲区,当Redis执行了写命令之后,会同时发给AOF缓冲区

和AOF重写缓冲区(在服务器创建子进程之后开始使用)。

这就是AOF后台重写!也即是BGREWRITEAOF命令。

Reference

《Redis设计与实现》

posted @ 2021-09-28 21:01  csgopher  阅读(56)  评论(0编辑  收藏  举报