redis 持久化机制
1.为什么需要持久化
redis中的数据全部保存在内存中,如果突然宕机,数据就会全部丢失.为了防止这种事情发生,我们需要一种机制保证在宕机发生之后,我们重启服务内存中的数据还可以恢复,这就是redis的持久化机制.
redis提供了三种持久化机制分别为RDB(Redis DataBase)方式,AOF(Append Only File)方式和混合模式.
2.RDB方式
rdb模式的特点是使用二进制的格式全量的保存redis中的数据,在存储上非常的紧凑,从而使可以控制文件的大小不至于太大.
1.触发方式
1.手动触发:
1.1 save
该命令使用主线程进行快照生成,所以在命令执行期间redis不能处理其他命令,直到rdb过程结束,所以在生产环境中尽量少使用该命令.
1.2 bgsave
bgsave命令执行的时候会fork出子线程,主线程会直接返回,生成rbd快照的工作交由子线程处理,所以该命令只会在fork子线程的时候阻塞,这个过程一般很短,所以如果想要生成rdb快照,可以考虑使用bgsave命令代替save命令,减少阻塞时间.
2.自动触发
2.1 在redis.conf中配置了save m n 参数.即在m秒内有n次修改则自动生成rdb文件.
2.2 主从复制.当从服务器第一次连接上主服务器时,首先需要一次全量的复制,这时候会在主服务器上触发rdb生成快照
2.3 在优雅的关闭redis服务的时候,如果没有开启其他持久化机制,redis会默认进行bgsave操作.
2.原理
当redis触发了快照生成操作时,主进程判断当前是否已经存在正在执行的子进程,如果存在,那么主进程直接返回,如果不存在正在执行的子进程,那么就fork一个新的子进程进行持久化数据,fork过程是阻塞的,fork操作完成后主进程即可执行其他操作;子进程先将数据写入到临时的rdb文件中,待快照数据写入完成后再原子替换旧的rdb文件;同时发送信号给主进程,通知主进程rdb持久化完成,主进程更新相关的统计信息。主线程调用glibc的fork方法fork出子线程,在子线程fork出的一瞬间,主线程和子线程共享内存中的数据,当主线程接收其他命令对数据进行操作的时候,主线程会复制出共享的数据页面,,然后进行修改,这样不会对子线程中的内存页造成影响,子线程中的数据页中的数据还是刚从主线程中分离出来的样子,这样就可以保证子线程生成的rdb文件为主线程fork出子线程的一瞬间的快照.
3.配置
save m n
当m秒之内有n个数据修改操作,则自动生成rdb文件,如果想禁用rdb功能,只需要配置 save "" 即可
rdbcompression yes|no
当进行rdb生成快照时,是否对生成的文件进行压缩.因为redis时cpu密集型服务,而压缩文件也会照成大量的cpu消耗,如果redis上的请求较多建议不开启该操作,
dir path
rdb文件保存的路径
dbfilename fileName
设置生成的rdb文件的名称,和上面的dir参数配合使用
stop-writes-on-bgsave-error yes|no
当rdb操作失败是,主线程是否还可以继续接收写相关命令,如果设置为yes,则当rbd失败时,redis不在接收写相关的命令
4.优点
1.rdb为全量备份,而且是以二进制的格式保存的,所以rdb文件占用空间会比较小,所以非常适合容灾备份.
2.rdb文件中保存的是数据,所以恢复速度也很快.
3.在执行bgsave的时候是由主线程fork出子线程进行快照生成,所以并不会影响主线程执行其他操作,只会在fork出子线程的时候阻塞.
5.缺点
1.rdb中保存的是二进制数据所以无法直接查看文件的内容
2.rdb并不能实时的保存数据,在rdb文件中会丢失执行快照操作的命令之后的其他写数据操作.
3.rdb文件并不能很好的兼容redis的所有版本,不同版本之间的rdb文件可能并不能通用.
4.aof
原理
和rdb中保存二进制格式的内存中的数据不同,aof模式保存的时redis执行的写命令,即aof中保存了redis自动开始到当前所有的写相关的命令,当redis需要恢复数据时,只需要重复执行以下这些命令就可以了.
Redis 会在收到客户端修改指令后,先进行参数校验,如果没问题,就立即将该指令文本存储到 AOF 日志中,也就是先存到磁盘,然后再执行指令。这样即使遇到突发宕机,已经存储到 AOF 日志的指令进行重放一下就可以恢复到宕机前的状态.
因为aof日志写入和命令的执行都是主线程完成的,所以开启aof之后不可避免的将影响主线程执行命令的效率.
当redis将aof日志内容写入aof文件的时候,其实只是写入了一个文件的缓冲区中,具体什么时间将缓冲区中的内容真正写入到磁盘上这个可以选择由redis触发或者由系统决定,这个可以配置,详情可以参考配置小节.
重写
因为aof文件中记录的是操作日志,所以aof会在redis运行时间长了之后变的很大.当aof文件过大时会造成aof文件继续写入的效率变低,并且如果aof文件很大那么恢复数据的时候也会很慢,为了减小aof文件的大小,redis提供了重写机制,来减小aof文件的大小.相关配置可以在配置小节中查看.
触发自动 AOF 重写条件
1.没有 BGSAVE 命令在进行。
2.没有 BGREWRITEAOF 在进行。
3.当前 AOF 文件大小大于 server.aof_rewrite_min_size (默认值为 64 MB)。
4.当前 AOF 文件大小和最后一次 AOF 重写后的大小之间的比率大于等于指定的增长百分比
AOF重写机制的实现原理
首先调用 fork 指令,来创建一个子进程,然后子进程根据当前内存中的数据生成对应指令,并记录在一个临时 AOF 文件中,不需要依赖原有的 AOF 文件 (即不需要读取原有的 AOF 文件进行分析或指令合并)主进程会持续将新的变动同时写入到内存和原有的 AOF 文件中当子进程完成了临时 AOF 文件的创建后,会发送信号给主进程,此时主进程会往临时 AOF 文件中同步增量变动最后使用临时 AOF 文件替换原有的 RDB 文件我们可以通bgrewriteaof 指令来手动触发 AOF 文件的重写.AOF重写日志,不会阻塞线程,AOF日志由主线程写回磁盘,AOF重写过程是由后台进程bgrewriteaof来完成的。主线程fork出后台的bgrewriteaof子进程,fork会把主线程的内存拷贝一份bgrewriteaof子进程,这里面就包含了数据库的最新数据。然后,bgrewriteaof子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。所以aof在重写时,在fork进程时是会阻塞住主线程的
配置
appendonly yes|no
当appendonly为yes时redis启用aof备份
appendfilename filename
指定生成的aof文件的名称
appendfsync always|everysec|no
什么时候把aof文件缓冲区的内容写入的磁盘上.因为缓冲区中的内容实际上还没有写入到磁盘,如果这个时候宕机,那么数据也会丢失,所以这个时间不应该设置的太长,redis提供了三种方案.第一种时每秒中写入一次,这个时最常用的,另外一个是每执行一次命令就写入一次,因为fsync命令非常慢所以这个不推荐使用.还有一个是不主动写入到磁盘,而是由系统决定什么时候写入,
auto-aof-rewrite-percentage 100
aof 文件自上一次重写后文件大小增长了100%,则再次触发重写机制,比如说,上次AOF文件容量为100M,这次文件已经到200M了,则自动触发重写机制
auto-aof-rewrite-min-size 64mb
aof文件至少要达到64M才会触发自动重写,文件太小,恢复速度很快,重写意义不大
优点
aof默认的保存策略时每秒一次,所以aof的数据安全性要比rdb高.并且aof中记录的时文本格式的命令,这样查看起来会比较方便,而且数据恢复的时候也不受redis版本的限制,所有aof文件都是通用的.
缺点
引文aof中记录的时操作数据的命令,所有aof文件会明显大过rdb文件,并且在数据恢复的速度上也明显慢于rdb文件.如果redis开启了aof因为aof实在主线程中记录的,所以会影响redis执行命令的效率.
5.混合持久化
重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小.于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。