缓存数据库REDIS之二:AOF重写原理

Posted 云来云去-起飞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了缓存数据库REDIS之二:AOF重写原理相关的知识,希望对你有一定的参考价值。

目录

一、为什么使用AOF

二、AOF 重写作用

三、AOF文件重写后为什么会缩减文件大小

四、AOF 文件重写的实现

4.1.AOF执行流程

4.2.实现原理

 4.3.AOF缓冲区和缓存区的作用及效用

4.4.AOF新旧替换时,主进程状态

4.5.AOF的三个策略配置

4.6.AOF文件重写的触发条件及触发方式

4.6.1触发条件

4.6.2触发方式

五、总结


一、为什么使用AOF

        RDB持久化是将进程数据写入文件,而AOF持久化,则是将Redis执行的每次写、删除命令记录到单独的日志文件中,查询操作不会记录; 当Redis重启时优先执行AOF文件中的命令来恢复数据。
       与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案。

二、AOF 重写作用

         AOF 持久化是通过保存被执行的写命令来记录数据库状态和相关数据,所以AOF文件的大小随着时间推进会越来越大;那么通过AOF文件进行还原出数据库的时间也会相应增加。 为了解决AOF文件体积膨胀的问题,Redis提供了AOF重写功能:Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个文件所保存的数据库状态是相同的,但是新的AOF文件不会包含任何浪费空间的冗余命令,通常体积会较旧AOF文件小很多。

三、AOF文件重写后为什么会缩减文件大小

  • 过期的数据不再写入文件
  • 无效的命令不再写入文件:如有些数据被重复设值(set mykey v1, set mykey v2)、有些数据被删除了(sadd myset v1, del myset) 等。
  • 多条命令可以合并为一个:如sadd myset v1, sadd myset v2, sadd myset v3可以合并为sadd myset v1 v2 v3。


四、AOF 文件重写的实现

        AOF重写并不需要对原有AOF文件进行任何的读取,写入,分析等操作,这个功能是通过读取服务器当前的数据库状态来实现的。


4.1.AOF执行流程

  • 命令追加(append): 将Redis的写命令追加到缓冲区aof_buf;
  • 文件写入(write)和文件同步(sync):根据不同的同步策略将aof_buf中的内容同步到硬盘;
  • 文件重写(rewrite): 定期重写AOF文件,达到压缩的目的。

(1) 命令追加 (append)
        Redis先将写命令追加到缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈。
        命令追加的格式是Redis命令请求的协议格式,它是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点。

       在A0F文件中,除了用于指定数据库的select命令 (如select0为选中0号数据库) 是由Redis添加的,其他都是客户端发送来的写命令。

(2)文件写入(write) 和文件同步 (sync)
        Redis 提供了多种AOF缓存区的同步文件策略,策略涉及到操作系统的write函数和fsync函数,说明如下:
          为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。

4.2.实现原理

        首先创建新的AOF文件是通过aof_rewrite函数来实现,但是这个函数会进行大量的写入操作,所以调用这个函数的线程将被长时间的阻塞,因为Redis服务器使用单线程来处理命令请求;所以如果直接是服务器进程调用AOF_REWRITE函数的话,那么重写AOF期间,服务器将无法处理客户端发送来的命令请求。(说白了,就是占用主线程,导致其他请求无法被处理)
        为了解决以上问题,那么Redis将AOF重写程序放到子进程(后台)里执行,这样子进程进行AOF重写期间,主进程可以继续处理命令请求;子进程带有主进程的数据副本,使用子进程而不是线程,可以避免在锁的情况下,保证数据的安全性。
       那么问题又来了,使用子进程进行AOF重写的问题,子进程在进行AOF重写期间,服务器进程还要继续处理命令请求,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的AOF文件中的数据不一致。

       为了解决这种数据不一致的问题,Redis增加了一个AOF重写缓存,这个缓存在fork出子进程之后开始启用,Redis服务器主进程在执行完写命令之后,会同时将这个写命令追加到AOF缓冲区和AOF重写缓冲区 。

 4.3.AOF缓冲区和缓存区的作用及效用

        AOF缓冲区的内容会定期被写入和同步到AOF文件中,对现有的AOF文件的处理工作会正常进行从创建子进程开始,服务器执行的所有写操作都会被记录到AOF重写缓冲区中;
        完成AOF重写之后当子进程完成对AOF文件重写之后,它会向父进程发送一个完成信号,父进程接到该完成信号之后,会调用一个信号处理函数,该函数完成以下工作:

        将AOF重写缓存中的内容全部写入到新的AOF文件中;这个时候新的AOF文件所保存的数据库状态和服务器当前的数据库状态一致;

4.4.AOF新旧替换时,主进程状态


       对新的AOF文件进行改名,原子的覆盖原有的AOF文件;完成新旧两个AOF文件的替换。
当这个信号处理函数执行完毕之后,主进程就可以继续像往常一样接收命令请求了。在整个AOF后台重写过程中,
只有最后的“主进程写入命令到AOF缓存”和“对新的AOF文件进行改名,覆盖原有的AOF文件。”这两个步骤(信号处理函数执行期间)会造成主进程阻塞,在其他时候,AOF后台重写都不会对主进程造成阻塞,这将AOF重写对性能造成的影响降到最低。

4.5.AOF的三个策略配置

vim /etc/redis/6379.conf
---729---
● appendfsync always:
命令写入aof_ buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了Redis的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低SSD的寿命。

● appendfsync no:
命令写入aof_ buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。

● appendfsync everysec:
命令写入aof_ buf后调用系统write操作,write完成后线程返回; fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置。

4.6.AOF文件重写的触发条件及触发方式

4.6.1触发条件

  •         没有BGSAVE命令(RDB持久化)/AOF持久化在执行;
     
  •          没有BGREWRITEAOF在进行;
  •          当前AOF文件大小要大于server.aof_rewrite_min_size(默认为1MB),或者在redis.conf配置了auto-aof-rewrite-min-size大小;
  •          当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比(在配置文件设置了auto-aof-rewrite-percentage参数,不设置默认为100%)
  •         如果前面三个条件都满足,并且当前AOF文件大小比最后一次AOF重写时的大小要大于指定的百分比,那么触发自动AOF重写。

4.6.2触发方式

  •        手动触发:直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞。
  •        自动触发:通过设置auto-aof - rewrite-min-size选项和auto- aof - rewrite- percentage选项来自动执行BGREWRITEAOF。
  •        只有当auto-aof- rewrite- -min-size和auto-aof -rewrite-percentage两个选项同时满足时,才会自动触发AOF重写,即bgrewriteaof操作。

五、总结

  •         AOF重写的目的是为了解决AOF文件体积膨胀的问题,使用更小的体积来保存数据库状态,整个重写过程基本上不影响Redis主进程处理命令请求;

  •        AOF重写其实是一个有歧义的名字,实际上重写工作是针对数据库的当前状态来进行的,重写过程中不会读写、也不适用原来的AOF文件;

  •        AOF可以由用户手动触发,也可以由服务器自动触发。

以上是关于缓存数据库REDIS之二:AOF重写原理的主要内容,如果未能解决你的问题,请参考以下文章

缓存数据库REDIS之二:AOF重写原理

Redis进阶学习06--分布式缓存--上

Redis 干货领域从底层彻底吃透 AOF 重写 (原理篇)

缓存-redis持久化机制(RDB和AOF)

缓存-redis持久化机制(RDB和AOF)

Redis之AOF重写及其实现原理