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也是比较小。