Redis之持久化

为什么需要持久化

Redis的所有数据是存储在内存里面的,Redis的持久化,为了防止机器忽然的宕机、断电使Redis内存中的数据来不及存储在硬盘而导致数据的丢失

哪些持久化方法

Redis有两种持久化机制
快照
AOF

快照 snopashotting

跟名字一样,就是将内存中的数据全部备份到硬盘的一个文件中,我们可以在redis.conf文件中设置

1
2
3
4
5
save 60 1000  # 当60秒内写入1000个请求时,触发BGSAVE
stop-write-on-bgsave-error no # 当创建快照文件失败后是否继续执行写命令
rdbcomparession yes # 是否对快照文件进行压缩
dbfilename dump.rdb # 备份数据的文件
dir ./ # 存储的路径

创建快照的方法

1、 客户端发送BGSAVE命令来创建一个快照,Redis会调用fork创建一个子进程,子进程负责快照备份并写入硬盘,父进程继续处理客户端的请求
2、客户端发送SAVE指令,这时Redis只会进行快照的备份,在快照完成之前,不会再响应任何其他命令
3、如果用户在redis.conf中设置了SAVE配置(也就是上面那段代码),比如save 60 1000 从Redis最近一次创建快照之后算起,当60秒内有1000次写入,就会自动触发BGSAVE命令。当设置了多个SAVE配置,只要有一个满足就会执行BGSAVE
4、当Redis通过SHUTDOWN命令接收到关闭服务器或者接受到标准的TEMP信号时,会执行一个SAVE命令
5、当Redis服务器连接另一个Redis服务器,并向对方发送SYNC命令来开始一个复制操作时,如果主服务器没有执行BGSAVE操作,就会自己执行BGSAVE操作

注意:快照会丢失数据的,因为在创建快照的时候,如果有指令写入,此时数据是不会被备份的,因为Redis是使用系统的COW(Copy On Write)

Fork

上面说当Redis执行BGSAVE命令时,会调用系统glibc的函数fork产生一个子进程,来完成快照的创建,而父进程继续处理请求
当子进程创建出来的时候,它不会修改内存中的数据结构,只会对数据进行遍历读取然后序列化到硬盘,如果此时父进程有请求指令处理时,Redis就会调用系统的COW(Copy on Write )机制来进行数据段页面的分离。页面是内存中存储的一种形式,当一个页面中的数据在父进程中被修改时,父进程就会把该页面复制出来,然后在该页面里面操作数据,此时子进程快照备份的是没有被修改的页面,所以父进程在创建快照期间的所有操作是不会被备份的

AOF

AOF(append-only file)只追加文件,它存储的是命令不是数据,也就是说,Redis会将成功执行的命令写入到一个文件中,然后把该文件的命令从头到尾在另一台Redis服务器运行一遍,就能恢复原来的数据
AOF配置可以通过设置redis.conf来配置

1
2
3
4
5
6
7
appendonly  no                       # 是否开启AOF持久化
appendfysnc everysec # 多久将写入内容同步到硬盘
no-appendsync-on-rewrite no # 在对AOF进行同步的时候是否执行同步操作
appendfilename "appendonly.aof" # 存储AOF的文件
# 下面两条命令可以配置自动执行AOF重写
auto-aof-rewrite-percentage 100 # AOF的体积比上一次文件重写之后的体积大了一倍(100%)
auto-aof-rewrite-min-size 64mb # AOF文件的体积大于64MB

上面第三条配置,是配置是否开启文件同步,文件同步是强制Redis将缓存区里的数据(AOF数据会先写入缓存)马上写入硬盘,此时会阻塞客户端的请求

appendfsync同步频率

上面配置的第二句,设置了多久将缓存中的文件写入到硬盘。AOF是先写入硬盘的缓存的,然后才从缓存写入硬盘,所以如果发生宕机,会发生AOF数据丢失的风险,所以设置同步频率很重要,设置同步频率是调用Linux的glibc的fsync(int id)函数,只要Redis调用了该函数就能保证aof日志不丢失,因为会强制系统写入,还发生阻塞了其他请求
三种同步频率:

  • always:每个Redis写命令都要同步到硬盘,这严重降低了Redis的速度,不建议
  • everysec:每秒执行一次同步,将一秒内的请求命令写入硬盘,推荐使用,就算是发送故障,丢失的数据也能控制在1秒内
  • no:让系统自己决定何时进行同步

重写AOF(AOF瘦身)

随着系统的运行,AOF日志文件的体积会不断增大,这时可以通过重写AOF来减小AOF的体积。
用户可以发送BGREWRITEAOF命令,该命令会移除AOF文件中冗余的命令来重写(rewrite)AOF,BGREWRITEAOF跟BGSAVE很相似,也是开启一个子进程后台运行
除了手动开启BGREWRITEAOF,还可以通过配置redis.conf来开启,也就是上面最后两条配置
auto-aof-rewrite-percentage 100 #AOF的体积比上一次文件重写之后的体积大了一倍(100%)
auto-aof-rewrite-min-size 64mb # AOF文件的体积大于64MB
当上面这两个条件满足时,就会开启BGREWRITEAOF

快照跟AOF的比较

AOF恢复数据的速度远不如快照,当时快照会发生数据丢失,两者各有各的优点
在Redis4.0后,引入了混合持久化,也就是快照跟AOF并存,当需要Redis持久化时,先进行快照备份,在快照备份期间,所有的写命令都将写入AOF
当需要重启或者恢复数据时,先进行快照恢复,等快照恢复进行完了就进行AOF恢复,完美解决!