Redis的AOF持久化机制

AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行 AOF文件中的命令达到回复数据的目的。

AOF主要解决 数据持久化的实时性。

流程如下:

1.所有的写命令会追加到aof_buf(缓冲区)中。

2.AOF根据对应的策略向硬盘做同步操作。

3.随着AOF文件越来越大,需要定期对 AOF文件 进行重写,达到压缩的目的。

4.当Redis服务器重启时,可以加载 AOF 文件进行数据恢复。

==================================================================================A

AOF命令写入的内容直接是文本协议格式。

疑问:

1.AOF为什么直接采用文本协议格式?

答:1.文本协议具有很好的兼容性,

        2.开启AOF后,所有写入命令 都 包含 追加操作,直接采用协议格式,避免了二次处理开销

        3.文本协议具有可读性,方便直接修改和处理。

2.AOF 为什么把命令追加到 aof_buf 中?

答:Redis使用单线程响应命令,如果每次写AOF文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载。

先写入aof_buf中,还有一个好处:Redis提供了多种缓冲区同步硬盘的策略,在性能和安全性方面做出平衡【三种策略下面有讲】。

还是在redis.conf文件:找到:APPEND(追加)

接着往下:

默认是关闭的,改成 yes就开启了,

一旦开启备份,就会产生一个文件名称:appendonly.aof

三种同步策略:

1. always:只要有写操作,就会记录在aof日志文件中,会很慢,但是保证数据的完整,一般不用

2. everysec:默认的操作,为最多每秒调用一次fsync,这种模式性能并不是很糟糕,一般也不会产生毛刺,这归功于Redis引入了BIO线程,所有fsync操作都异步交给了BIO线程

重写:

         随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入重写机制来压缩文件体积。

AOF文件重写 是 把 Redis进程内的数据转化为命令 同步到新的 AOF文件的过程。

         重写后的 AOF文件为什么可以变小?

         答:1.进程内已经超时的数据不在写入文件。

                2.清除了一些无效命令

                3.多条写命令可以合并为批量写命令 eg. lpush list v1 lpush list v2 lpush list v3 合并为一条写入命令 lpush list v1 v2 v3。【为了防止单条命令过大造成客户端缓冲区溢出,对于 list,set,hash,zset等类型的操作,以64个元素为界限拆分为多条】。

      AOF重写降低了文件的占用空间,【更小的AOF文件可以更快地被redis加载】

      AOF重写过程可以手动触发和自动触发:

          手动触发:直接调用:bgrewriteaof命令

          自动触发:下文有

              

no-appendfsync-on-rewrite no 表示:

正在重写时,不要把新的操作同步到日志文件里,【如果改成 yes,可能会导致数据丢失,下文会细讲】

重写时,这两个条件必需全部满足,才能触发【自动触发】

auto-aof-rewrite-percentage:表示 当前AOF文件空间(aof_current_size) 和上一次重写后AOF文件空间(aof_base_size) 的比值(100 表示两倍)

第二个:表示 运行 AOF重写时文件最小体积(auto-aof-rewrite-min-size),默认是64MB

自动触发时机=aof_current_size  >auto-aof-rewrite-min-size&&(aof_current_size - aof_base_size)/aof_base_size>=auto-aof-rewrite-percentage

         重写流程:

流程说明:

1):执行AOF重写请求

   如果当前进程正在执行 AOF重写,请求不执行,并返回如下响应:

    ERR Background append only file rewriting already in process

 如果当前进程正在执行 bgsave 操作,重写命令延迟到 bgsave 完成之后再执行,返回如下响应:

       Background append only file rewriting shceduled

2):父进程执行fork创建子进程,开销等同于 bgsave过程。

3.1):主进程完成 fork操作后,继续响应其他命令。所有修改命令依然写入 AOF缓冲区,并根据 appendsync策略同步到硬盘,保证原有 AOF机制正确性。

3.2):由于 fork操作运用了写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,Redis使用 “AOF重写缓冲区” 保存这部分新数据,防止 新 AOF 文件生成期间丢失这部分数据。

4):子进程根据内存快照,按照 命令合并规则 写入到 新的 AOF文件。每次批量写入硬盘数据量由配置 aof-rewrite-incremental-fsync 控制,默认为32MB,防止单次刷盘数据过多,造成硬盘阻塞。

5.1):新的 AOF 文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。

5.2):父进程把 AOF重写缓冲区的数据写入到新的 AOF文件。

5.3):使用新的 AOF文件替换老的文件,完成 AOF重写。

========================================================================

关于 3.2) 使用 AOF重写缓冲区【是将no-appendfsync-on-rewrite 设置成 yes】 和上文的 设置为 no-appendfsync-on-rewrite no

有冲突 的解答:

bgrewriteaof机制,在一个子进程中进行aof的重写,从而不阻塞主进程对其余命令的处理,同时解决了aof文件过大问题。

现在问题出现了,同时在执行bgrewriteaof操作和主进程写aof文件的操作,两者都会操作磁盘,而bgrewriteaof往往会涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,现在no-appendfsync-on-rewrite参数出场了。如果该参数设置为no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。

如果设置为yes呢?这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。丢失多少数据呢?在linux的操作系统的默认设置下,最多会丢失30s的数据。

因此,如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为yes。如果应用系统无法忍受数据丢失,则设置为no。

发布了55 篇原创文章 · 获赞 5 · 访问量 6055

猜你喜欢

转载自blog.csdn.net/weixin_42528855/article/details/103748124