Redis 设计与实现 (三)--持久化

时间:2022-06-17 03:45:54

RDB 持久化

 一、生成RDB

  cmd:SAVE  --阻塞进程,执行完,才能有效接收客户端命令。

  cmd:  BGSAVE  --非阻塞,开启子进程保存。

          客户端如果发送SAVE和BGSAVE命令直接拒绝。

          BGWRITEAOF命令再BGSAVE执行完才能执行。  

 二、载入RDB

  服务器启动时自动执行,检测到RDB文件就会自动加载。

  如果开启AOF,优先使用执行AOF。

  AOF关闭的情况下,才会执行RDB。

三、自动间隔性保存

  save设置:一定条件后执行BGSAVE命令进行保存

  默认设置:

    save 900 1  //900秒内,进行一次修改,触发保存BGSAVE

    save 300 1  //300秒内,10次修改,触发保存BGSAVE  

    save 60  10000   //60秒内,1w次修改,触发保存BGSAVE 

struct saveparam {
time_t seconds; //秒数
int changes;//变化次数
};

还有两个参数:

dirty --上次数据库触发保存命令修改数

lastsave -- 最后一次执行save时间

PORT_LONGLONG dirty;                /* Changes to DB from the last save */ 
 time_t lastsave;                /* Unix time of last successful save */

还有一个定时器默认100毫秒来检测是否满足save条件的方法:serverCron

int serverCron(struct aeEventLoop *eventLoop, PORT_LONGLONG id, void *clientData) 

四、RDB文件结构

  | REDIS | db_version | database | EOF | check_sum |

  RDB文件开头是REDIS,来判定是否是RDB文件。

  db_version  版本号

  databse 包含任意多个数据库(键值对)

  EOF RDB文件结束标志

  check_sum  校验长度

AOF 持久化

一、命令持久化,保存redis 的写命令

二、命令追加

  redis 执行完写命令,将命令按照一定协议格式追加到 aof_buf 缓冲区

sds aof_buf;      /* AOF buffer, written before entering the event loop */

三、AOF文件写入与同步

  resid 服务器进程是一个事件循环

  文件事件:接受命令和输出内容

  时间事件:负责定时任务

  文件事件执行写命令,这样会追加命令到aof_buf 缓冲区,在这写命令结束之前会调用flushAppendOnlyFile 函数判断是否从缓冲区回写到AOF文件。

  写入策略有三个:

    always: 将aof_buf 缓冲区所有内容写入并同步到AOF文件。

    everysec(默认): 将缓冲区内容写入,超过一秒钟,并进行同步。

    no: 将缓冲区的所有内容同步,但是不同步。

四、AOF 载入以及数据还原

  1、创建一个伪客户端

  2、分析aof文件 并解析一条命令

  3、伪客户端执行此命令

  4、循环执行2和3

五、AOF重写

  AOF 存储写命令,体积会膨胀,恢复数据库的时间也会变长。

  新建文件AOF ,去除冗余命令,合并命令。达到缩减文件目的。

六、AOF后台重写

  处理命令请求会因为这个aof重写造成阻塞。

  另起一个子进程,进行aof重写。但是会存在数据不一致的问题,子进程在处理重写一条命令后,同时主进程依然在写当操作对象的命令。造成数据不一致。

  解决方案:开辟aof重写缓存区

  命令会直接写入aof缓存区和aof重写缓存区,这样可以读取缓存区命令进行处理。类似队列,先写入队列进行待处理。

  生成的写命令-->aof缓冲区  -->写入同步到aof文件

  生成的写命令-->aof重写缓冲区 -->  写完  -->发送信号给父进程 --> aof重写缓冲区写入新aof文件 -->原子覆盖旧aof文件

  

  父进程处理命令,保存aof,使用子进程,覆盖重写aof,达到性能最佳不阻塞,同时生成的新aof也是比较小。