redis是一个键值对的内存数据库服务器,它将数据库状态存储在内存之中,但是如果一旦服务器出现问题意外crash或者重启那么内存中的数据库状态将全部丢失,为了解决这个问题,redis提供了持久化方案,将内存中数据库状态同步到磁盘保障数据
redis提供了两种持久化方案:rdb,aof
- rdb方式:将数据库状态(数据库中键值对)保存为一个经过压缩的二进制文件
- aof方式:将数据库写命令保存为一个固定格式的文件
redis-rdb持久化
rdb文件创建
redis通过两个命令来用于生成rdb文件:
- save:
- save命令在生成rdb文件期间会阻塞redis主进程,直到rdb文件创建完成之前redis主进程无法处理任何客户端请求
- 由函数rdb.c/rdbSave函数执行、
函数rdbSave本身就会阻塞进程
- bgsave:
- bgsave命令通过由主进程fork出一个子进程来执行生成rdb文件,生成rdb文件期间不会阻塞主进程
- 由函数rdb.c/rdbSave函数执行
- 问题:bgsave命令执行期间服务器如何处理save,bgsave,bgrewriteaof三个命令
- bgsave命令执行期间Redis服务器拒绝执行save命令,防止主进程和子进程同时执行rdbSave函数导致资源竞争
- bgsave命令执行期间Redis服务器拒绝执行bgsave命令,防止两个子进程同时执行rdbSave函数导致资源竞争
- bgsave和bgrewriteaof命令吧態同时执行
- bgsave执行期间bgrewriteaof命令会被延后,直到bgsave执行完成才可以执行bgrewriteaof
- bgrewriteaof执行期间,bgsave命令会被丢弃
rdb文件载入
rdb文件载入实在服务器启动的时候就会自动执行,所以redis并没有专门的用关于rdb文件载入的命令,只要redis服务器检测到rdb文件就会自动载入rdb文件
rdb文件载入期间,主进程处于阻塞状态,直到载入完成才可以执行客户端命令
问题:如果rdb方式和aof方式同时开启,redis服务器如何使用持久化方式恢复的
- 如果aof方式开启,由于aof方式的实时性更高,所以redis会优先使用aof文件来恢复数据库
- 只有aof方式处于关闭状态,redis服务器才会使用rdb文件来做数据库恢复
rdb自动间隔性保存
由于bgsave在执行期间不会阻塞主进程,所以redis允许通过配置服务器配置save属性,让服务器在满足条件的情况下自动还行bgsave
配置放在redis.conf文件中,格式为:save <seconds> <changes>
- 当满足在seconds秒内,redis数据库执行过changes次修改,那么就会触发自动bgsave
- save属性可以设置多个,在设置多个的情况下,满足任意一个就会自动执行
- redis默认配置:
如何触发自动间隔性保存?
- redis的时间事件执行周期性的函数serverCron默认每100ms执行一次扫描。会检查设置的save属性是否满足
- 如果条件满足那么就会执行bgsave,否则继续周期扫描检测
redis-aof持久化
aof的持久化功能实现可以分为:命令追加,文件写入,文件同步三个步骤
- 命令追加:当aof功能处于打开状态,服务器在执行完写命令后,会将这个写命令追加到aof_buf内存缓冲区中
- 文件写入和文件同步:
- redis主进程本身就是一个事件循环event-loop
-
处理文件事件执行写命令,并追加到aof_buf
-
处理时间事件执行周期任务
-
结束事件循环前-调用flushAppendOnlyFile函数考虑将aof_buf内容写入和保存早aof文件中
-
flushAppendOnlyFile的函数行为由服务器配置:appendfsync属性决定,属性值不同则产生不同的行为
-
appendfsync=always:总是将aof_buf缓冲区内容同步写入到aof文件中
- 安全性最高,只会丢失一个事件循环内的数据
- 效率最差,大量的I/O操作
-
appendfsync=everysec:每秒周期的将aof_buf缓冲区同步的写入到aof文件中
- 安全性适中,丢失一秒内的写数据
- 效率适中
-
appendfsync=no:不执行将aof_buf缓冲区内容同步到aof文件的操作
- 安全性最差,丢失自上次之后所有数据
- 效率最高
-
-
aof文件的载入和数据还原
aof文件中包含了重建数据库的所有写口令,所以服务器只需要读入命令并且重新执行一遍aof文件中命令,就可以还原数据库
- 1:创建一个无网络连接的伪客户端:因为redis的命令执行能在客户端执行。所以利用伪客户端来执行aof文件中命令
- 2:从aof文件中分析并读取一条写命令
- 3:使用伪客户端执行读取到的写命令
- 4:循环执行2,3直到完全执行完所有aof文件中命令
aof重写
aof文件是通过记录写命令来实现持久化,但是存在一个问题:对同一个key在给定时间内会发生多次写操作,所以aof文件存在越变越大的问题,而体积过大aof文件对于redis服务器的压力会变大,所以需要解决这一弊端;最好的情况是无论执行多久,对于相同的key在aof文件中只存在一条有效的能够保障当前数据库状态的写命令,所以redis提供了重写功能
重写的实现:
- 理论依据:aof重写时通过读取当前服务器数据库状态来实现的
- 通过aof文件中的key从redis数据库中获取key的当前状态并将当前状态装换为写命令来实现
- 实际操作:
- redis提供了aof_write函数来实现redis-aof重写
- aof_write函数在执行期间会阻塞主进程
aof后台重写
由于aof_write在执行期间会阻塞主进程,而aof重写只是一种辅助手段,所以redis不希望重写阻塞主进程,所以提供aof后台重写功能,aof重写由主进程fork出的子进程来执行aof重写,主进程则继续接受和执行客户端命令
问题:aof后台重写期间主进程依旧执行写命令,导致数据状态最终不一致
- redis在aof后台重写期间会开启aof重写缓冲区
- 主进程在aof后台重写期间每执行一条写命令,都会将写命令同时发送到aof缓冲区和aof重写缓冲区
-
最终aof文件重写完毕后,会将aof重写缓冲区文件同步写入新aof文件,保证了最终一致
aof重写步骤
- 开始后台aof重写,主进程fork子进程开始执行bgrewriteaof命令
- 主进程将重写期间的写命令同时发送到aof缓冲求,aof重写缓冲区
- 子进程完成aof重写工作,向主进程发送一个信号
- 主进程接收到信号调用信号处理函数
- 重命名新的aof文件并原子覆盖旧aof文件
rdb的实时性小于aof文件,所以rb不适合做redis的容灾方案,适合做冷备
aof文件适合做容灾方案,因为最理想情况下,aof方案只会丢失一个事件循环里的数
来源:CSDN
作者:漫步星辰575654643
链接:https://blog.csdn.net/good575654643/article/details/103458791