redis-持久化

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提供了重写功能

重写的实现:

  • 触发条件:
    • 手动触发:执行bgrewriteaof命令
    • 自动触发:配置属性
      • auto-aof-rewrite-min-size :aof文件最小重写大小
      • auto-aof-rewrite-percentage:当前aof文件大小与最后一次重写后大小比率,100表示aof是上次重写时两倍才重写
  • 理论依据: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文件
  • 重命名新的aof文件并原子覆盖旧aof文件
  • 重写完成

如何合理使用持久化

rdb文件紧凑单一但是实时性弱,aof耐久实时性好但是体积会大,基于二者在性能,安全性,实时一致性上的特点,rdb更加适合做冷备份,非常便于数据库备份;aof适合做热备份,适合做容灾。但是小孩子才做选择,在线上生产环境当然是选择两种持久化方式同时开启使用,利用rdb来保存数据库数据副本,利用aof记录实时的命令

redis4.0混合持久化

4.0的新特性,将rdb与aof持久化方式二合一结合了两者的优点,可以快速加载同时避免丢失过多数据,缺点就是文件可读性差

新特性中aof文件会由两部分组成,一半是rdb格式,一半是aof格式

 

 混合持久化过程

  • 发生时间点:aof-rewrite被触发
  • 如何开启:aof-use-rdb-preamble yes (redis5.0默认开启)
  • aof-rewrite流程:
    • fork子进程遍历old-aof文件读取数据库状态写入new-aof文件
    • 在写new-aof期间新的写命令会记录在重写缓冲区中
    • 当写new-aof完成,子进程通知主进程,主进程将重写缓冲区数据写入new-aof文件
    • 重命名并原子替换old-aof
  • aof-rdb混合持久化:
    • fork子进程会以rdb的格式将数据库状态写入new-aof文件
    • 在写入new-aof期间新的写命令会记录在重写缓冲区中
    • 子进程以rdb格式同步数据库状态ok,通知主进程
    • 主进程会将重写缓冲区中增量命令以aof格式写入new-aof文件
    • 重命名并原子替换old-aof
  • aof-rdb混合持久化加载:
    • 加载方式依旧遵循优先aof文件
    • 当开启aof并开启混合持久化时优先加载混合aof文件
      • 混合aof文件以顺序加载
      • 先rdb后aof
    • 否则,由aof先aof,否则rdb

总结:

  • rdb优点:
    • 结构紧凑(二进制压缩文件)体积小,适合容灾恢复
    • 恢复大数据集时比aof快 (rdb记录的是数据库键值对信息)
    • 可以最大化redis性能(bgsave是fork子进程执行)
  • rdb缺点:
    • 快照数据,数据完整度不高,适合冷备不适合热备
    • 数据量大时,子进程耗费cpu越多,耗时越久
    • 文件二进制格式,可读性差
  • aof优点:
    • 数据完整度高(appendfsync=always丢失一个事件循环的数据)
    • 兼容性高(命令追加)
  • aof缺点:
    • 数据体积大,就算aof-rewrite(命令追加导致)
    • aof加载速度比rdb慢(一条条由伪客户端执行命令)
posted @ 2019-12-09 15:24  青衫磊落》  阅读(279)  评论(0)    收藏  举报