redis持久化
redis持久化有两种方式RDB和AOF
注意:我使用的版本是6.0.10,不同版本可能略有差别
RDB
RDB是指Redis DataBase,在指定的时间间隔内,将内存中数据的快照写入到磁盘dump.rdb的文件中,恢复时通过载入rdb文件来还原数据库状态。
rdb文件是一个经过压缩的二进制文件
redis会单独创建(fork)一个子线程来进行持久化,会先将数据写入到临时文件,持久化结束之后,将临时文件替换上次持久化好的文件(保存在dump.rdb文件中),RDB方式比AOF更加高效,但是可能会丢失最后一次持久化的数据
在这里fork的线程是根据当前线程fork的,包含了当前线程的所有数据、变量等
RDB配置
关于RDB的配置是在redis.conf中的快照(SNAPSHOTTING)模块中
1 | # |
rdb文件会存储在执行redis-cli的当前目录下的dump.rdb文件中,默认触发条件是
save 900 1 #15分钟内修改了1次
save 300 10 #5分钟内修改了10次
save 60 10000 #1分钟内修改了10000次当达到条件时会触发bgsave命令
也可以使用save或者bgsave命令来直接立即备份。
save命令是由主线程来做的,其他操作都会阻塞,直到rdb文件创建完毕,但是不会消耗额外的内存
bgsave是后台线程做的,其他操作可以正常执行,不会阻塞客户端命令
可以使用命令来检测rdb文件是否存在问题
1 | redis-check-rdb |
重启之后会直接加载本目录下的dump.rdb文件
bgsave命令
使用fork创建子进程;父进程继续接受并处理命令,子进程将内存数据写入临时文件;子进程写入所有数据后会用临时文件替换旧RDB文件
bgsave命令在执行时,服务器处理save、bgsave、bgrewriteaof这三个命令会与平时不同
- save命令不可执行,避免父子进程同时执行rdbsave,防止产生竞争条件
- bgsave命令不可执行,防止两个bgsave产生竞争条件
- 如果此时bgsave正在执行,bgrewriteaof会被延迟到bgsave执行完之后执行;如果bgrewriteaof正在执行,则bgsave命令会被拒绝, 为了防止两个子进程同时执行造成大量的磁盘写入操作
原理
使用fork()+copyonwrite
fork()
fork()是linux和unix的底层api,会fork出来一个子进程,共享那一刻的内存数据,且修改互相不可见
copyonwrite
主进程fork子进程之后,内核会把主进程中所有的内存页权限设置为read-only,当主进程写数据时,read-only会发生中断,将触发中断的内存页复制一份主进程来操作修改,其余的还是在共享内存内
优缺点
优点
- 数据紧凑,比较小,可以很方便的传送到另一个数据中心
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高
缺点
- 由于是每隔一段时间去备份的,如果redis意外挂掉的话,可能会丢失最后一次快照的所有修改
- fork的时候,内存中的数据被克隆一份,内存会是原来的两倍
- 耗时耗性能,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步脏数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io操作,可能会严重影响性能
停止RDB持久化的方式
1 | redis-cli config set save "" |
在进行rdb持久化是将内存数据完整的写入磁盘,并不是使用增量的方式,如果数据量大的话可能会有大量的磁盘IO操作
AOF
AOF是指Append Only File,以日志的形式记录写操作,只许追加文件内容,不许修改,redis启动时会读取该文件来根据日志文件内容重新将写指令执行一次以完成数据恢复(日志文件名称为appendonly.aof)
默认该方式没有开启
AOF配置
关于AOF的配置是在redis.conf中的APPEND ONLY MODE模块中
1 | ############################## APPEND ONLY MODE ############################### |
如果aof文件中存在一些错误的指令(由于网络原因等问题导致命令没有写完),可以使用命令进行修复aof文件
1 redis-check-aof --fix
aof比rdb具有更好的持久化性,在使用aof持久化方式时,redis会将每一个收到的写命令通过write函数追加到文件中,在redis重启时会将aof文件中的命令重新执行一遍
AOF实现
AOF持久化方式打开之后,服务器执行写命令会写在缓冲区的末尾(server.c中的redisServer中有一个aof_buf字段来作为缓冲区),serverCron函数会定时将aof_buf缓冲区中的数据写入到文件
重写机制
由于AOF采用的是日志追加,可能会导致日志文件越来越大,为了避免此情况,增加了重写机制,当AOF文件超过所设定的阈值之后,redis会启动AOF文件的压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof来执行
重写之后减少了磁盘占有量,而且可以加速数据恢复
redis在进行重写时会占用大量的cpu和内存资源
no-appendfsync-on-rewrite no 这个配置是指是否在每次fsync的时候都进行重写,但是这样会造成大量的磁盘IO,还有可能会造成对写操作的阻塞,所以一般该值不推荐修改为yes
重写步骤:
- redis调用fork,创建一个重写子进程,子进程将整个内存中的数据库内容用命令的方式重写了一个新的aof文件写入到一个临时文件中
- 父进程在处理client的时候,除了将写命令写入原来的aof文件中,还需要同时将写命令缓存起来(aof_rewrite_buf_blocks),写入原来的aof文件中是为了保证如果子进程重写失败不会出问题
- 当子进程把快照内容写完之后通知父进程,父进程将缓存的写命令追加写入临时文件
- 追加结束后父进程将临时文件替换老的aof文件,之后收到的命令也将写入新的aof文件中
优缺点
优点
- 写入日志的策略分为always、everysec、no,使用默认everysec,最多损失1秒的数据
- AOF文件有序的保存了对redis执行的所有操作,如果误操作了flushall命令,只要aof文件还没有被重写,那么只要停止服务器,删掉AOF文件末尾的flushall命令,重启redis,就可以将数据恢复到flushall之前的状态
缺点
aof文件远大于rdb文件,恢复速度慢
由于aof方式比rdb方式的更新频率高,所以如果开启了aof,那么在启动时会优先使用aof文件来还原数据库状态
混合模式
在redis4.0之后出现了rdb和aof混合模式,而且默认开模式是开启的
1 | aof-use-rdb-preamble yes |
开启后,AOF在重写时会直接读取RDB中的内容
运行过程:
通过bgrwriteaof完成,不同的是当开启混合持久化后,子进程会把内存中的数据以RDB的方式写入aof中,把重写缓冲区中的增量命令以AOF方式写入到文件,将含有RDB格式和AOF格式的AOF数据覆盖旧的AOF文件
新的AOF文件中,一部分数据来自RDB文件,一部分来自Redis运行过程时的增量数据
定时任务
在server.c中的serverCron函数是redis的一个定时任务,该函数处理了很多定时处理的命令。可以在配置文件中配置hz的值来配置每秒执行多少次,默认是10,即1秒执行10次,表示100ms一次
1 | /* This is our timer interrupt, called server.hz times per second. |