在 Redis 中 AOF 持久化功能默认是不开启的,需要我们修改 redis.conf 配置文件中的以下参数:
Redis 是先执行写操作命令后,才将该命令记录到 AOF 日志里的 :
优点:先执行写操作命令再记录日志的话,只有在该命令执行成功后,才将命令记录到 AOF 日志里,这样就不用额外的检查开销,不会出现语法错误等问题,保证记录在 AOF 日志里的命令都是可执行并且正确的
缺点:执行写操作命令和记录日志是两个过程,那当 Redis 在还没来得及将命令写入到硬盘时,服务器发生宕机了,这个数据就会有丢失的风险
写入AOF日志的过程 Redis 执行完写操作命令后,会将命令追加到 server.aof_buf 缓冲区;然后通过 write() 系统调用,将 aof_buf 缓冲区的数据写入到 AOF 文件,此时数据并没有写入到硬盘,而是拷贝到了内核缓冲区 page cache,等待内核将数据写入硬盘redis.conf 配置文件中的 appendfsync 配置项可以有以下 3 种参数可填:
Always,这个单词的意思是「总是」,所以它的意思是每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘;Everysec,这个单词的意思是「每秒」,所以它的意思是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘;No,意味着不由 Redis 控制写回硬盘的时机,转交给操作系统控制写回的时机,也就是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,再由操作系统决定何时将缓冲区内容写回硬盘。Always 策略的性能比较差,可靠性高,尽可能保证数据不会丢失
Everysec策略性能适中,宕机会丢失一秒的数据
No策略性能良好,宕机会丢失较多的数据
AOF重写机制AOF 日志是一个文件,随着执行的写操作命令越来越多,文件的大小会越来越大。
其中AOF日志中
Redis 为了避免 AOF 文件越写越大,提供了 AOF 重写机制,当 AOF 文件的大小 超过所设定的阈值后,Redis 就会启用 AOF 重写机制,来压缩 AOF 文 件。
AOF重写机制
读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到「新的 AOF 文件」
作用:
尽管某个键值对被多条写命令反复修改,最终也只需要根据这个「键值对」当前的最新状态,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这样就减少了 AOF 文件中的命令数量。最后在重写工作完成后。最后在重写工作完成后,将新的 AOF 文件覆盖现有的 AOF 文件。为什么重写 AOF 的时候,不直接复用现有的 AOF 文件,而是先写到新的 AOF 文件再覆盖过去?
如果 AOF 重写过程中失败了,现有的 AOF 文件就会造成污染,可能无法用于恢复使用。
AOF后台重写当 触发 AOF 重写时,比如当 AOF 文件大于 64M 时,就会对 AOF 文件进行重写,这时是需要读取所有缓存的键值对数据,并为每个键值对生成一条命令,然后将其写入到新的 AOF 文件,重写完后,就把现在的 AOF 文件替换掉。这个过程其实是很耗时的,所以重写的操作不能放在主进程
所以,Redis 的 重写 AOF 过程是由后台子进程 bgrewriteaof 来完成的,这样做有两个作用:
子进程进行 AOF 重写期间,主进程可以继续处理命令请求,从而避免阻塞主进程;父进程 使用fork 创建子进程时,父子进程是共享内存数据的,不过这个共享的内存只能以只读的方式,而当父子进程任意一方修改了该共享内存,就会发生「写时复制」,所以子进程在执行后台重写是不影响父进程。子进程是怎么拥有主进程一样的数据副本的呢?
当父进程 使用fork 创建子进程的时候,会将父进程中的页表 复制给子进程,因此父子进程它们的共享一块物理内存。
写时复制顾名思义,在发生写操作的时候,操作系统才会去复制物理内存,这样是为了防止 fork 创建子进程时,由于物理内存数据的复制时间过长而导致父进程长时间阻塞的问题。
重写子进程只会对这个内存进行只读,重写 AOF 子进程会读取数据库里的所有数据,并逐一把内存数据的键值对转换成一条命令,再将命令记录到重写日志(新的 AOF 文件)
重写 AOF 日志过程中,如果主进程修改了已经存在 key-value,此时这个 key-value 数据在子进程的内存数据就跟主进程的内存数据不一致了,这时要怎么办呢?
Redis 设置了一个 AOF 重写缓冲区,这个缓冲区在创建 bgrewriteaof 子进程之后开始使用
在重写 AOF 期间,当 Redis 执行完一个写命令之后,它会同时将这个写命令写入到 「AOF 缓冲区」和 「AOF 重写缓冲区」。
当子进程完成 AOF 重写工作(扫描数据库中所有数据,逐一把内存数据的键值对转换成一条命令,再将命令记录到重写日志)后,会向主进程发送一条信号。
主进程收到该信号后,会调用一个信号处理函数,该函数主要做以下工作:
将 AOF 重写缓冲区中的所有内容追加到新的 AOF 的文件中,使得新旧两个 AOF 文件所保存的数据库状态一致;新的 AOF 的文件进行改名,覆盖现有的 AOF 文件。