Hello World

Redis---持久化

1. 概述

  Redis 的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的持久化机制。

     Redis 的持久化机制有两种,第一种是快照,第二种是 AOF 日志。快照是一次全量备份AOF 日志是连续的增量备份

  快照是内存数据的二进制序列化形式,在存储上非常紧凑,而 AOF 日志记录的是内存数据修改的指令记录文本。AOF 日志在长期的运行过程中会变的无比庞大,数据库重启时需要加载 AOF 日志进行指令重放,这个时间就会无比漫长。所以需要定期进行 AOF 重写,给 AOF 日志进行瘦身。

2. RDB

2.1 RDB文件

  RDB持久化功能可以将redis在内存中某个时间点数据库状态保存到一个RDB文件, RDB文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态.

2.2 SAVE

  SAVE命令会阻塞Redis服务进程, 直到RDB文件创建完毕为止, 在阻塞期间, 服务器不能处理任何命令请求.

2.3 BGSAVE

  BGSAVE命令会派生出一个子进程, 然后子进程负责创建RDB文件, 父进程继续处理命令请求.

  基本原理: fork() + cow

  Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。这是 Linux 操作系统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的一瞬间,内存的增长几乎没有明显变化。

  子进程做数据持久化,它不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是父进程不一样,它必须持续服务客户端请求,然后对内存数据结构进行不间断的修改。

  这个时候就会使用操作系统的 COW 机制来进行数据段页面的分离。数据段是由很多操作系统的页面组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时那一瞬间的数据。

3. AOF

3.1 基本原理

  AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录。

  假设 AOF 日志记录了自 Redis 实例创建以来所有的修改性指令序列,那么就可以通过对一个空的 Redis 实例顺序执行所有的指令,也就是「重放」,来恢复 Redis 当前实例的内存数据结构的状态。

  Redis 会在收到客户端修改指令后,进行参数校验进行逻辑处理后,如果没问题,就立即将该指令文本存储到 AOF 日志中,也就是先执行指令才将日志存盘。这点不同于leveldb、hbase等存储引擎,它们都是先存储日志再做逻辑处理。 Redis 在长期运行的过程中,AOF 的日志会越变越长。如果实例宕机重启,重放整个 AOF 日志会非常耗时,导致长时间 Redis 无法对外提供服务。所以需要对 AOF 日志重写。

3.2 AOF重写

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

3.3 参数配置

  AOF 日志是以文件的形式存在的,当程序对 AOF 日志文件进行写操作时,实际上是将内容写到了内核为文件描述符分配的一个内存缓存中,然后内核会异步脏数据刷回到磁盘的。 这就意味着如果机器突然宕机,AOF 日志内容可能还没有来得及完全刷到磁盘中,这个时候就会出现日志丢失。下面是三种配置

  Linux 的glibc提供了fsync(int fd)函数可以将指定文件的内容强制从内核缓存刷到磁盘。只要 Redis 进程实时调用 fsync 函数就可以保证 aof 日志不丢失。但是 fsync 是一个磁盘 IO 操作,它很慢!如果 Redis 执行一条指令就要 fsync 一次,那么 Redis 高性能的地位就不保了。 

  所以在生产环境的服务器中,Redis 通常是每隔 1s 左右执行一次 fsync 操作,周期 1s 是可以配置的。这是在数据安全性和性能之间做了一个折中,在保持高性能的同时,尽可能使得数据少丢失。

  还有一种是永不 fsync——让操作系统来决定何时同步磁盘, 这个是根据系统刷新输出缓冲区的时间来决定的,一般来说是30s

  1. no:不要立刻刷,只有在操作系统需要刷的时候再刷。比较快。
  2. always:每次写操作都立刻写入到aof文件。慢,但是最安全。
  3. everysec:每秒写一次。

4. 指令冲突

4.1 执行BGSAVE期间

  1. 发送的SAVE命令会被服务器拒绝
  2. 发送的BGSAVE命令会被服务器拒绝
  3. 发送的BGREWRITEAOF命令会被延迟到BGSAVE命令执行完毕后执行

  禁止SAVE和BGSAVE命令同时执行是为了避免父子进程同时执行两个 rdbSave 调用, 防止产生竞态条件

4.2 执行BGREWRITEAOF期间

  1. 发送的BGSAVE命令会被服务器拒绝

  这两个命令的实际工作都是由子进程执行, 操作方面并没有什么冲突, 禁止两个同时执行只是性能方面的一个考虑.

5.0 Redis 4.0 混合持久化

  重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间

  Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。

  于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。

6. 数据还原

  当AOF持久化功能开启时, 服务器优先使用AOF文件来还原数据库状态,

  当AOF持久化功能关闭时, 服务器才会使用RDB文件来还原数据库状态

posted @ 2018-08-27 18:59  小小忧愁米粒大  阅读(281)  评论(0编辑  收藏  举报
瞅啥瞅,好好看书