贵金属行情
公众号:技术and生活

复习redis持久化-AOF

引言

为了使得线上的数据更加的安全可靠,我们都知道Redis的数据是保存在内存中的,一旦Redis的服务器挂掉,会导致数据的丢失,所以我们在使用Redis的时候,一般会开启持久化功能,来保证数据不丢失,下边分享一下RDB和AOF两个持久化方式的知识点,本文承接上文聊AOF。

AOF持久化及配置

与RDB持久化方式不同的是,AOF持久化是通过保存Redis服务器的写和选择db的命令实现。

首先简单聊一下操作系统的文件写入和同步

操作系统为了提高文件写入效率,当我们在往一个文件写入内容的时候,实际是先把内容放到了写入缓冲区,当达到缓存区大小限定或者时间条件后,操作系统才将内容同步到磁盘中。这种做法有效的提高了写入速度,但是从我们写文件到文件真正的落地到磁盘是有时间间隔的,这样就带了了安全问题,如果服务器在将数据从缓冲区同步到文件之前异常关机,那就会导致写入缓冲区内的数据丢失。

Redis AOF同步

在Redis配置文件中,有一个配置项为appendfsync,其可选值为always、everysec、no

AOF的持久化过程,先执行追加、再是文件写入、最后是文件的同步。

  • 追加,是将Redis服务器的写命令追加到服务器的aof_buf缓冲区末尾。

  • 文件写入,是将上边aof_buf中的指令,按顺序写入到AOF文件中,及appendonly.aof文件中,这个在配置文件可以找到。

  • 最后是文件同步,由每个事件循环控制,在serverCron函数内,这个就取决于上边appendfsync的配置

    • always:只要aof_buf内容,就将内容写入并同步到文件中,效率最低,频繁磁盘io,但是数据最安全,最多丢失一个事件内的数据。
    • everysec:虽然将aof_buf的内容写入到了文件,但不是立即同步,看当前时间和上次间隔是不是达到了1秒,达到了在做同步。折中,不是频繁的io操作,数据相对安全,会丢失1秒的数据。
    • no:只对aof_buf中的内容做写入操作,并不做同步工作,同步工作交由系统执行。效率最高,数据最不安全,一旦丢失,丢失的最多。

AOF文件的载入就很简单,就是起一个伪客户端,依次执行AOF文件里的命令即可。

AOF文件的重写

AOF持久化的方式,很容易让aof文件变得很大,同一个key,比如来来回回被设置删除,更改内容,AOF持久化的方式都要将每一条写命令保存下来,这就容易造成文件的快速膨胀,因此需要对AOF重写,来压缩文件大小。

AOF文件的重写并不是真的对旧文件重写,而是直接分析当前内存数据,得到AOF文件。可以使用命令是服务器立即完成AOF文件的重写,或者后台运行。

基本过程

​ 主进程fork(同RDB持久化,因为要分析当前内存数据,所以要fork出一个子进程)一个子进程,然后开始分析内存数据,并生成指令写入到AOF文件中,有一点需要注意,因为Redis服务器存在一个输出端缓冲区的东西,所以如果某个key非常的大,为了避免缓冲区溢出,采用多条命令落地,比如a是个队列,有是三个值,可以生成三条push指令就行追加,至于多少条分一个指令,可以看源码的宏AOF_REWRITE_ITEMS_PER_CMD(为64)。

​ 这时候主进程依然可以监听命令,提供服务,那问题来了,如果在执行AOF的rewrite过程有新的数据修改,那岂不最后新的AOF文件和当前内存里的数据就不一致了么?这时候主进程会增加两个事情,本身主进程在收到指令后,除了操作内存数据外,还要将数据写入到AOF缓冲区(依旧向老的AOF文件追加),如果此时正在进行AOF重写的话,会新增向AOF重写缓冲区追加写指令和监听AOF重写完成的信号两件事情。

​ 如果AOF重写子进程执行完毕,会发送信号给主进程,主进程收到信号后,会将AOF重写缓冲区内的内容追加到新的AOF文件中,并原子的用新文件替换老的AOF文件,然后继续接受指令工作。这样就保证了AOF文件内容和在完成AOF文件重写那一刻的内存数据一致。

问题

由于需要fork子进程,一样会像RDB持久化一样阻塞主进程,另外由于在执行完AOF重写后,主进程需要将重写期间的写指令,也就是AOF重写缓冲区的内容追加到新的AOF文件中,这就又阻塞住了主进程,AOF重写缓冲区内的内容越大,追加的时间就越长,阻塞的时间也就越长,对于高并发写入场景,你可能会看服务器的内存暴涨,这有些不友好。

延伸

  • AOF持久化数据安全性

    这种方式持久化,数据的安全性取决于appendfsync的配置,其最高安全性能保证只丢一个事件周期的数据,但是效率最低,折中的办法是接受一秒内的数据丢失,采用everysec配置。

  • AOF持久化比RDB持久化好么

    不一定,从上边的描述中我们看到,如果你的服务是高并发写服务,而且数据量大,那AOF持久化,也不太友好,原因就是这个AOF重写缓冲区,因为这里存的那些重写后输入的写指令,如果重写的时间越长,重写缓冲区内的数据就越大,导致内存持续增加。

    但如果你的服务是,写入比较少,但是数据量还是不小,那这个AOF持久化模式看起来要比RDB持久化好些,因为它能保证你的数据更安全,一旦异常,丢失的内容少的多。

    还有一点,AOF文件的重新载入速度要比RDB文件慢,AOF文件载入时相当于一条条的执行命令,而RDB文件就是二进制文件,载入相当快速。

    当你了解了RDB和AOF持久化的基本原理后,还是要结合实际使用情况使用。

  • 其他建议

    • 还是要优化Redis的使用方式,不要使用超长的key和超长的value

    • 能用数字代表的尽量用数字代表,比如1-1000的数字

    • 尽量将Redis设计成你的缓存服务器,而不是存储,数据没有可以从mysql等数据库恢复

    • 尽量给每个key都有过期时间,不要长期保存基本没有访问的数据,这个过期时间也要注意打散,不要让大量的key在同一时间过期。

yunsonbai wechat
公众号:技术and生活