微信公众号:DBA随笔
线上的Redis服务被用来当做缓存用,缓存有一个缺点,就是一旦断电,缓存中的数据将全部丢失。通常情况下,缓存中的数据是允许丢失的,但是有些业务场景下,无法容忍数据丢失,这个时候,就需要我们将缓存中的内容保存起来,或者说不保存,但是你能够把它“恢复出来”。
既然要恢复数据,那我们可以从数据库中,例如mysql中,将所有的数据重新读入Redis中即可,这个方法本身是可行的,但是有2个缺点,其一是会对数据库产生不必要的读取压力,其二是从数据库中"植入"到缓存中的过程,可能会比较长,这个过程中,应用程序需要容忍响应慢的问题。
看来直接恢复,有些难度,Redis中索性将这些缓存中的数据,通过2种机制保存起来,"持久化"到磁盘中,这样下次恢复数据的时候,就会比较快。这2种机制,分别是AOF和RDB,今天来看AOF机制。
AOF全称是Append Only File,它类似MySQL中的binlog,将MySQL中执行过的命令保存起来,等到我们想要恢复数据的时候,再从AOF日志中将这些命令重新写入到Redis实例中即可。AOF文件中保存的是在Redis中执行过的命令。假设我们执行一个hello world的命令,如下:
127.0.0.1:6380> set hello world OK
它对应的AOF文件内容就是:
*2 # *2代表下面的命令有2个关键字:分别是"select" 和数字0 $6 # $6表示select关键字含有6个字符,也就是6个字母; SELECT # SELECT就是系统帮我们补充的关键字 $1 # $1表示数字0含有1个字符 0 # 数字0 *3 # -----这里开始第二个命令---*3表示这个命令有3个关键字,分别是set、hello、world $3 # $3表示set含有3个字符,也就是3个字母; set # set就是我们输入的关键字 $5 # $5表示接下来的关键字hello含有5个字符 hello # hello就是我们输入的关键字 $5 # $5表示接下来的关键字world含有5个字符 world # hello就是我们输入的关键字
总体上说,这个set hello world的命令的AOF文件,包含2个部分:第一部分是系统补充的select 0,表示选定数据库编号0,Redis默认有16个db编号,如下:
127.0.0.1:6380> select 0 OK 127.0.0.1:6380> select 15 OK 127.0.0.1:6380[15]> select 16 (error) ERR invalid DB index
第二部分是我们手工执行的set hello world命令。
再补充一点,AOF文件中每行输出之间的换行符是 。
到这里,我们了解了AOF文件中的内容。
我们知道MySQL使用基于WAL(write ahead log)技术的两阶段提交模式来保证数据的可靠性,也就是先写redo log ,再写binlog,再标记redo log为commit的方法来确保数据的可靠性。Redis中,正好相反,它采用的是先写数据库,再写AOF的方法来保证数据的可靠性。
Redis中写内存和写AOF日志的示意图如下:
看到这里,你可能会说,先写数据库,再写日志,如果针对某条命令,数据库写完之后,还没来的及写日志,数据库就宕机了,那么这条日志没有记录到AOF中,再次利用AOF恢复的时候,不就丢数据了么?确实存在这种风险,但是Redis可以通过配置策略来将这种风险控制到最小。下面我们就来看AOF日志文件写入到磁盘的一些细节。
当客户端执行了写入命令后,写入的内容会进入到AOF的buffer中,执行完一条命令之后,Redis会调用刷盘函数flushAppendOnlyFile来进行刷盘,而这个函数中配置了一个刷盘的策略,这个策略由Redis的参数appendfsync来确定,如下:
127.0.0.1:6380[15]> config get appendfsync 1) "appendfsync" 2) "everysec"
这个参数可以配置为以下几个值:
always:Redis在每个事件循环的时候都要将aof_buffer中的内容写入aof文件,并且同步到磁盘中
everysec:Redis在每个事件循环的时候都将aof_buffer中的数据写入到aof文件,并且每1s要在子线程中对aof文件进行一次同步,它也是Redis的默认值。
no:Redis在每个事件循环的时候都将aof_buffer中的数据写入到aof文件,由操作系统控制何时对aof文件进行一次同步
其中,no值模式下,aof文件写入的速度是最快的,因为不会每个事件都强制刷盘,而always值模式下,aof文件写入的效率是最慢的,因为每个事件都要刷盘,会影响Redis的性能,但是提高了安全性。总之:
安全性考虑:always > everysec > no
持久化效率:always < everysec < no
AOF重写机制
关于这个内容,之前的文章中有详细说明,这里不再赘述,给出文章链接:
AOF重写机制