Redis两种持久化过程及AOF重写

本文详细介绍了Redis的两种持久化机制:RDB(快照持久化)和AOF(追加日志持久化)。RDB在指定条件触发,生成内存快照,适合全量备份,但存在数据丢失风险。AOF记录所有写操作,保证实时性,但文件体积可能增大。AOF重写机制用于压缩文件,减少存储空间。在持久化过程中,fork操作可能导致短暂阻塞,需要监控子进程内存消耗并调整相关配置以确保数据安全和性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、RDB持久化

RDB持久化:将内存中的数据生成快照保存到硬盘上。
触发条件:

  • 手动触发:通过redis-cli执行BGSAVE命令触发;
  • 自动触发:
    – 配置文件中的“save m n”配置项:在m秒时间内发生了n次写入操作;
    – 主从复制结构中,从节点进行全量复制时,会触发主节点执行BGSAVE命令进行RDB持久化;
    – 通过redis-cli执行shutdown命令时,如果没有开启AOF持久化功能则自动执行BGSAVE进行RDB持久化。

1.1、RDB持久化过程

RDB持久化过程

①某个条件触发RDB持久化;
②如果没有正在执行的子进程(如RDB/AOF子进程),Redis父进程fork一个子进程,用于持久化过程,fork过程中,Redis父进程会短暂阻塞。通过INFO stats命令的“latest_fork_usec”记录上一次fork操作的耗时,单位是微秒;
③Redis父进程fork操作完成,将不再阻塞父进程,父进程可以继续响应其它命令;
④子进程生成RDB文件,根据Redis父进程内存中的内容生成快照,并替换原有RDB文件。LASTSAVEINFO persistence命令的“rdb_last_save_time”记录上一次RDB持久化的时间戳;
⑤子进程执行完成,发送信号告知Redis父进程,Redis父进程更新INFO persistence中的rdb相关信息。

1.2、RDB持久化相关配置

  • 何时进行RDB持久化:“save m n”:在m秒时间内发生了n次写入操作;
  • RDB文件存储路径:”dir /usr/local/redis/data”,Redis运行时通过CONFIG SET dir ***更改;
  • RDB文件名称:“dbfilename dump_6379.rdb”,Redis运行时通过CONFIG SET dbfilename ***更改文件名;
  • 是否对RDB文件进行压缩:“rdbcompression [yes|no]”;
  • 是否对RDB文件进行CRC64校验:“rdbchecksum [yes|no]”;

1.3、RDB持久化优缺点

优点:

  • RDB是Redis在某个时间点上内存数据的快照,非常适合备份、恢复和全量复制;
  • RDB恢复数据的速度比AOF快很多;

缺点:

  • RDB持久化每隔一段时间才会自动运行,无法做到实时/秒级持久化;
  • 持久化过程需要fork操作,会阻塞Redis进程,频繁执行成本较高;
  • 存在新老版本Redis无法兼容RDB文件的问题。

二、AOF持久化

AOF持久化:将写指令记录到特定文件,在重启或恢复数据时再逐条执行AOF文件中的写指令。解决了RDB持久化无法实现实时性的问题,是目前的主流持久化方式。
Redis重启时,会优先从AOF文件将数据加载到内存。

2.1、AOF持久化过程

AOF持久化过程
①所有的写指令会追加(append)到aof_buffer缓冲区中;
②aof_buffer缓冲区中的内容会根据相应的策略同步到硬盘的AOF文件中;
③当AOF文件达到一定大小时会进行重写,达到压缩的目的。

2.2、缓冲区同步策略

Redis提供了三种同步策略:

  • always:每次写指令写入aof_buffer都会调用系统fsync同步到AOF文件。虽然保证了数据安全,但需要更高性能的硬盘;
  • everysec:写指令写入aof_buffer调用系统write操作,由专门线程每秒调用一次fsync同步文件操作。是Redis默认的配置,兼顾了性能和安全;
  • no:写指令写入aof_buffer后调用系统write操作,由操作系统决定何时同步到硬盘。

关于系统调用write和fsync:

  • write:延迟写,在将数据写入系统缓冲区后,由操作系统调度何时写入磁盘;
  • fsync:强制硬盘同步。

2.3、AOF持久化相关配置

  • appendonly [yes|no]:是否启用AOF持久化,默认关闭;
  • appendfilename “appendonly_6379.aof”:AOF文件的名称;
  • appendfsync [no|always|everysec]:缓冲区同步策略,默认为“everysec”

2.4、AOF追加阻塞

通常会使用“everysec”作为AOF持久化的缓存同步策略。这种方式中,Redis使用一个单独的线程每秒执行fsync操作,同步数据到硬盘。
当系统资源繁忙时,fsync同步操作也会受到影响,Redis主线程会对比上次AOF同步的时间,如果在2秒内,主线程会直接返回;如果超过2秒,主线程将会阻塞,直到同步操作完成。
所以在系统资源繁忙时,“everysec”配置最多可能丢失2秒数据,而不是1秒。

三、AOF重写机制

因为采用了AOF追加方式,会导致AOF文件越来越大。Redis提供了AOF重写机制,当AOF文件的大小超过所设定的阈值时,redis就会启动AOF重写进行文件的内容压缩,只保留可以恢复数据的最小指令集。

3.1、重写机制如何压缩文件

  • 多条写指令合并为一个:lpush list a、 lpush list b、 lpush list c合并为lpush list a b c;
  • 只保留数据的最终写入命令:set a1;set b1;del a1最终只保留set b1

3.2、重写触发的条件

  • 手动执行BGREWRITEAOF命令;
  • 配置项自动触发。

相关的配置项:

  • auto-aof-rewrite-percentage 100:代表当前AOF文件大小和上一次重写后AOF文件大小的比值;
  • auto-aof-rewrite-min-size 64mb:触发AOF重写的文件最小值,默认是64MB。

INFO persistence中记录了当前AOF文件大小:aof_current_size和上一次重写后的AOF文件大小:aof_base_size,自动触发时机:aof_current_size>auto-aof-rewrite-minsize并且(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewritepercentage

3.3、AOF重写过程

AOF重写过程
①某个条件触发AOF重写;
②如果没有正在执行的AOF重写过程或BGSAVE操作,Redis父进程fork一个用于重写的子进程;
③Redis父进程会继续响应其他指令,默认的配置项“no-appendfsync-on-rewrite no”,决定了所有写指令仍然写入AOF缓冲区中,并根据同步策略将缓冲区数据写入硬盘,保证原来AOF机制正常运行;
同时由于Linux的写时复制(copy-on-write)特性,用于重写的子进程,只能共享fork操作时主进程的内存。而主进程仍然在响应指令,所以Redis使用“AOF重写缓冲区”(aof_rewrite_buffer)保存这些新的指令,防止重写期间的数据丢失;
④子进程根据当时的内存快照将写指令写入一个临时AOF文件,配置项“aof-rewrite-incremental-fsync”控制着每次写入硬盘的数据量为32MB,防止单次写入数据过多造成硬盘阻塞;
⑤子进程写入完成后通知Redis主进程,主进程更新INFO persistence信息中的相关内容;
⑥主进程将aof_rewrite_buffer中的数据写入到临时AOF文件;
⑦使用临时AOF文件替换原AOF文件,重写完成。

四、持久化过程中的问题

4.1、fork造成的阻塞

在RDB持久化和AOF重写时都会调用fork创建子进程,而在fork操作时,Redis主进程会被阻塞,虽然时间很短。但对于流量很大的场景下,如果fork操作耗时超过1秒,对线上应用的延迟影响将会很明显。通过INFO stats命令的“latest_fork_usec”指标可以查看最近一次fork操作的耗时,单位是微秒。
为了减少fork操作耗时,需要通过“maxmemory”参数控制Redis实例最大可用内存,因为Redis占用内存越多,fork操作需要复制的内存页表也越大。同时需要为系统预留足够的内存,避免物理内存不足导致fork操作失败。
设置sysctl vm.overcommit_memory=1允许内核可以分配所有的物理内存,避免Redis进程执行fork操作时因系统剩余物理内存不足而失败。
另外,由于Linux的大页内存(THP)机制,会在写时复制期间消耗更多的内存,Redis建议关闭THP。在CentOS7系统的禁用方法为:

echo "never" > /sys/kernel/mm/transparent_hugepage/enabled
echo "never" > /sys/kernel/mm/transparent_hugepage/defrag

4.2、监控子进程内存消耗

不管是RDB还是AOF重写都会消耗内存,消耗的内存量可以查询日志得出:

RDB相关日志:
8928:M 25 Dec 2020 14:05:19.620 * Background saving started by pid 8944
8944:C 25 Dec 2020 14:05:20.884 * DB saved on disk
8944:C 25 Dec 2020 14:05:20.888 * RDB: 1 MB of memory used by copy-on-write
8928:M 25 Dec 2020 14:05:20.962 * Background saving terminated with success
AOF重写相关:
8945:C 25 Dec 2020 14:05:22.670 * SYNC append only file rewrite performed
8945:C 25 Dec 2020 14:05:22.672 * AOF rewrite: 1 MB of memory used by copy-on-write
8939:S 25 Dec 2020 14:05:22.692 * Background AOF rewrite terminated with success
8939:S 25 Dec 2020 14:05:22.693 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
8939:S 25 Dec 2020 14:05:22.693 * Background AOF rewrite finished successfully

需要注意的是,AOF重写会用到AOF重写缓冲区,所以AOF重写时消耗的内存应该包括重写内存和AOF重写缓冲区占用内存。如上:1MB+0.00MB。

4.3、no-appendfsync-on-rewrite

该参数表示在AOF重写时不会将AOF缓冲区中的数据同步到磁盘。默认关闭,即在AOF重写时,会对AOF缓冲区中的数据做同步磁盘操作,这在很大程度上保证了数据的安全性。
但在数据量很大的场景,因为两者都会消耗磁盘IO,对磁盘的影响较大,可以将其设置为“yes”减轻磁盘压力,但在极端情况下可能丢失整个AOF重写期间的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值