1.RDB持久化

RDB持久化是把当前进程数据生成快照保存到硬盘的过程。触发RDB持久化的过程分为手动和自动触动。

触发的命令

1)save命令:阻塞当前Reid服务器,直到RDB过程完成为止,对于内存比较大的实例来说是会造成很长时间的阻塞
     运行save命令对应的redis日志如下:
     DB saved on disk.    
  2) bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。这个的阻塞只发生在fork阶段,一般时间很短。
     可以手动触发bgsave命令,当然也可以后台自动触发
 	  1)save m n 表示m秒内数据集存在n此修改时,就触发一次bgsave
      2)如果从节点执行全量复制的操作,主节点需要自动执行bgsave生成RDB文件并发送给从节点
      3)执行debug reload命令重新加载Redis时,也会自动触发save操作
      4)默认情况下,执行shutdown命令时,如果没有开启AOF持久化命令功能则自动执行bgsave

bgsave的流程说明

1)首先执行bgsave命令会判断是否存在一个正在执行的子进程,如RDB/AOF子进程,如果存在,bgsave命令就直接返回
    2)fork出来一个子进程,fork操作中父进程会阻塞,通过info stats命令可以查看latest_fork_usec选项,可以获取最近一个fork操作的耗时,单位是微秒
    3)父进程fork完成后,bgsave命令返回Background saving started 信息并不阻塞父进程,可以继续响应其他命令
    4)子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换,执行lastsave命令可以获取最后一次执行生成RDB的时间,可以对应info 统计的rdb_last_value_time.
    5) 进程发送信号,告诉父进程完成了,父进程更新统计信息,具体见Persistenct下的Info rdb.*

RDB文件的处理

RDB文件保存在dir配置指定的目录下,文件名通过dbfilename配置指定,也可以在运行期,执行config set dir{newdir},config set dbfilename{newFileName)运行期动态执行,当下次运行是RBB文件会保存在新的目录下
 压缩:redis默认采用LZF算法对生成RDB文件做压缩处理,压缩后的文件远远小于这个内存大小,默认开启,可以通过参数config set /rdbcompression{yes | no } ,建议在线上开启,因为这样体积较小,方便传给子节点做全量同步

RDB的优缺点

优点:
    1)RDB是一个紧凑压缩的二进制文件,代表的是Redis在某个时间点上的数据快照,非常适用于备份,全量复制的场景,并可以把RDB文件拷贝到远程机器或者文件系统保存,用于灾难恢复
    2)redis恢复RDB的速度要快于AOF
 缺点:
    1)数据安全性,因为RDB不能做到实时同步,因为创建fork子进程是一个重操作,不能经常执行,效率很低
    2)RDB使用二进制格式保存文件,redis版本存在多个格式的redis版本,存在老版本的rdb文件不能再新版本的redis中使用。

2.AOF持久化

以独立日志的方式记录每次的写命令,重启时候再重新加载AOF文件中的命令达到恢复数据的目的,AOF的只要作用就是解决了数据的实时性,目前已经是Redis持久化的主流方式。

开启AOF

修改配置 appendonly yes,默认不开启。
    AOF文件名通过appendfilename配置设置,默认的文件名是appendonly.aof,保存路径同RDB持久化方式一致。

AOF的工作流程有哪些

1.命令写入aof缓冲区   (append命令)
       aof写入的内容直接就是文本协议的格式(好处:直接将输入写到文件中,可以降低二次处理开销。可读性强)
       为什么需要这一步写入缓存呢?
          --这是因为写入缓存的话,可以比直接写入磁盘性能要好一些。可以让用户在性能和安全上去做选择
  2.文件同步    (sync命令)
       提供了多种文件同步的策略,由参数appendfsync控制
        1)always   命令写入aof_buf中,调用系统fsync命令同步aof文件,fsync完成后线程返回(性能低)
        2)everysec  命令写入aof_buf中,调用系统write操作,write完成后返回,fsync同步文件操作由其他线程专门每秒调一次(每秒一次,理论只会丢失最多一秒的数据,但是实际可能最多可以丢失两秒的数据,这是因为主线程会做判断,就是判断上一次的aof操作的时间距离现在是否是2秒钟了,如果超过两秒那么主线程也不接收数据了)
        3)no  命令写入aof_buf中,就直接返回,不对aof_buf做fsync命令,同步操作由操作系统负责,通常最长周期是30秒。(从不,安全性太低)
       write操作会触发延迟写机制,linux在内核提供页缓冲区用来提高磁盘的性能。write操作在写入系统缓冲区后直接返回,同步硬盘操作依赖于系统调度机制。比如,缓冲区写满了,或者特定周期刷新缓冲区
       fsync针对单个文件操作。做强制硬盘同步,fsync将阻塞直到写入硬盘完成后返回,保证数据的持久化
       除了write和fsync,还有sync,fdatasync操作
  3.文件重写    (rewrite命令)   
  4.重启加载    (load命令)
  5.具体流程:
      1)将所有的写入命令都追加到aof_buf(缓冲区中)。
      2)AOF缓冲区根据对应的策略向硬盘做同步操作
      3)随着AOF的文件越来越大,需要对文件进行重写,达到压缩的目的
      4)当redis服务器重启时,可以加载AOF文件进行数据恢复

重写机制

就是当命令不断写入AOF,文件会越来越大,为了解决这个问题,redis引入了aof重写机制压缩文件体积,AOF文件重写是把redis进程内的数据转换成写命令同步到新AOF文件的过程。
   为什么文件会变少?
        1)之前不要的数据不再写入文件
        2)一些无效命令,如 del key hedl ky2 srem keys 等,重写使用进程内的数据直接生成,这样新的aof文件只保留最终数据的写入命令
        3)多条命令会何为一条,但是为了防止单条命令过大导致客户端缓冲区溢出,对于List set hash zset等类型,以64个元素为界拆分为多条
触发命令
1)bgrewireof
      2)根据auto-aof-rewrire-min-size(表示运行aof重写时文件最小体积)和 suto-aof-rewrite-percentage(代表当前aof文件空间和上一次重写后的比值  aof_current>auto_aof_rewrite_min_size && (aof_current_size-aof_base_size)/aof_base_size>=auto_aof_rewrite-size)参数确定自动触发,也就是说当前大小与上次aof之后的大小的差值与上一次aof后大小的比值是否大于比率。
重写的执行流程:
1)执行aof重写请求,如果当前进程正在执行AOF重写,请求不执行并返回如下响应:
        ERR Background append only file rewriting already in progress
      如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成后再进行
    2)父进程执行fork创建子进程,开销等同于bgsave过程
    3.1)主进程fork操作完成之后,继续响应其他命令,所有修改命令依然写入AOF缓冲区并根据appendfsync策略同步到硬盘,保证原有AOF机制的正确性
    3.2)由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据,但是由于父进程依然响应命令,redis使用AOF重写缓冲区保存这部分新数据,防止新AOF文件生成期间丢失这部分数据
    4)子进程根据内存快照,按照命令合并规则写入新的AOF文件,每次批量写入磁盘数据量由配置aof_rewrite_incremental-fsync控制,默认为32MB,防止单次刷盘数据过多造成硬盘阻塞
    5.1)新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息,具体可见info persistence中的aof_*
    5.2)父进程把AOF重写缓冲区的数据写入到新AOF文件
    5.3)使用新AOF文件替换老文件,完成AOF重写
重启加载
RDB和AOF都可以用于数据恢复。
   流程说明:
        1)AOF持久化开启且存在AOF文件,优先加载AOF文件,打印如下日志:DB loaded from append only file : 5 seconds.
        2)AOF关闭或者AOF文件不存在时候,加载RDB文件,打印如下日志: DB loaded from disk : 5 seconds
        3) 加载AOF/RDB文件成功后,Redis启动成功
        4)AOF/RDB文件存在错误时,Redis启动失败并打印错误信息
AOF的追加阻塞
当开启AOF持久化的时候,常用的同步策略就是everysec,用于平衡性能和数据安全性。对于这种方式,redis使用另外一条线程每秒执行fsync同步磁盘,当系统硬盘资源阻塞的时候,会造成主线程阻塞。
   分析:1)主进程负责写入AOF缓冲区
        2)AOF线程负责每秒执行一次同步操作,并记录最近一次的同步时间
        3)主线程负责对比上次的AOF同步时间
           如果距离上次同步成功在2秒内,则直接返回
           如果距离上次同步成功在2秒外,则主线程阻塞,直到同步操作完成
   所以,其实最多可能会丢失2秒的数据,而且如果硬盘fsync操作阻塞的话,可能会造成主线程阻塞。