Redis持久化:RDB和AOF

Redis的持久化机制有两种,第一种是快照,第二种是AOF日志。快照是一次全量备份,AOF日志是连续的增量备份。快照是内存数据的二进制序列化形式,在存储上非常紧凑,而AOF日志记录的是内存数据修改的指令记录文本。AOF日志在长期的运行过程中会变得无比的庞大,数据库重启时需要加载AOF日志进行指令重放,这个时间就会无比漫长,所以需要定期进行AOF重写,给AOF日志瘦身。 

redis是单线程程序,在服务线上请求的同时还需要进行持久化的操作。持久化的同时内存数据结构还在改变,例如一个大型的hash字典正在持久化,结果一个请求过来把它删掉了,可是还没有持久化完,为了防止这种情况的发生,redis使用操作系统的多进程COW(Copy On Write)机制来实现快照持久化。

RDB

什么是RDB?

 

 

Redis持久化:RDB和AOF_第1张图片

RDB的触发机制:

  • save(同步):执行save命令时会生成一个RDB文件(二进制)但是会阻塞其他的命令,在数据量较大的时候会造成一定的阻塞,如果存在老的RDB文件会用新的文件替换到老的文件,复杂度是O(N)
  • bgsave(异步):执行bgsave命令时会fork()一个子进程来生成一个RDB文件,不会阻塞其他的命令,如果存在老的RDB文件会用新的文件替换到老的文件,复杂度是O(N)
  • 自动:当满足设置的一个条件时就会创建一个bgsave命令来生成一个RDB文件,如下图所示:

Redis持久化:RDB和AOF_第2张图片

注意:

以下三种方式也会触发RDB:

1. 全量复制

2. debug reload

3. shutdown 

AOF

什么是AOF?

AOF日志存储的是Redis服务器的顺序指令序列,AOF日志只记录对内存进行修改的指令记录,如果实例宕机会通过“重放”来恢复Redis当前实例的内存数据结构的状态。

Redis 会在收到客户端修改指令后,进行参数校验,逻辑处理,如果没有问题,就立即将该指令文本存储到AOF日志中,也就是说,先执行指令然后再将日志存盘,如下图所示:

Redis持久化:RDB和AOF_第3张图片

AOF的三种策略

AOF的日志是以文件的形式存在的,当AOF的日志文件进行写操作的时候,实际上是将内容写到了内核为文件描述符分配的一个内存的缓存中,然后内核会异步将脏数据刷回到磁盘的,Linux的glibc提供了fsync函数可以将指定文件的内容强制从内核缓存刷到磁盘,fsync主要有下面三种策略:

  • always:redis会将写命令刷新到缓冲区,每条命令都会fsync到硬盘。
  • everysec(配置的默认值):redis会将写命令刷新到缓冲区,每秒把缓冲区的命令fsync到硬盘。
  • no:redis会将写命令刷新到缓冲区,由操作系统决定什么时候把缓冲区的命令fsync到硬盘。

对比

命令 always everysec no
优点 不丢失数据 每秒一次fsync,丢1秒数据 不用管
缺点 IO开销大,一般的sata盘只有几百TPS 丢1秒数据 不可控

 

 

 

 

AOF重写 

redis提供了bgrewriteaof指令用于对AOF日志进行瘦身,其原理就是开辟一个子进程对内存进行遍历,转换一系列Redis的操作指令,序列化到一个新的AOF日志文件中。序列化完毕后再将操作期间发生的增量AOF日志追加到这个新的AOF日志文件中,追加完毕后就立即替代旧得到AOF日志文件了,瘦身工作就完成了,如下图所示:

Redis持久化:RDB和AOF_第4张图片

AOF重写作用:

  • 减少硬盘占用量
  • 加速恢复速度

AOF重写实现两种方式:

bgrewriteaof

Redis持久化:RDB和AOF_第5张图片

AOF重写配置

配置名 含义
auto-aof-rewrite-min-size AOF文件重写需要的尺寸
auto-aof-rewrite-percentage AOF文件增长率

 

 

 

统计名 含义
aof_current_size AOF当前尺寸(单位:字节)
aof_base_size AOF上次启动和重写的尺寸(单位:字节)

 

 

 

 

需要同时满足下列条件才会自动触发

aof_current_size > auto-aof-rewrite-min-size

(aof_current_size - aof_base_size) / aof_base_size > auto-aof-rewrite-percentage

AOF 重写流程:

Redis持久化:RDB和AOF_第6张图片

RDB和AOF的对比

命令 RDB AOF
启动优先级
体积
恢复速度
数据安全性 丢数据 根据策略决定
轻重

 

 

 

 

 

 

 

fork

什么是fork?

redis在持久化时会调用glibc的函数fork一个子进程,快照持久化交给子进程处理,父进程继续处理客户端的请求。

子进程做数据持久化不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是父进程不一样,它必须持续服务客户端的请求然后 对内存数据结构进行不间断的修改,这时候就会使用操作系统COW机制来进行数据段页面的分离,如下图所示,数据段是由很多操作系统的页面组合合成,让父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时的那一瞬间的数据。随着父进程修改操作的持续进行,越来越多的共享页面被分离出来,内存就会持续增长,但是也不会超过原有数据内存的2倍大小。另外,Redis实例里冷数据占的比例往往是比较高的,所以很少会出现所有的页面都被分离的情况,被分离的往往只有其中的一部分页面。

Redis持久化:RDB和AOF_第7张图片

子进程因为数据没有变化,它能看到的内存里的数据在进程产生的一瞬间就凝固了,再也不会改变,这也是为什么Redis的持久化叫“快照”的原因了。

fork操作:

  • 同步操作
  • 于内存息息相关:内存越大耗时越长(与机器类型有关)
  • info:latest_fork_usec:上一次执行fork的时长

改善fork:

  • 优先使用物理机或者高效支持fork操作的虚拟化技术
  • 控制redis实例最大可用内存:maxmemory
  • 合理配置linux内存分配策略:vm.overcommit_memory=1
  • 降低fork的频率:例如放宽AOF重写机制的触发时机,不必要的全量复制

AOF追加阻塞

Redis持久化:RDB和AOF_第8张图片

你可能感兴趣的:(redis,redis,持久化,AOF,RDB)