Redis持久化机制

Redis速度快,很大一部分原因是因为它所有的数据都存储在内存中。如果断电或者宕机,都会导致内存的数据丢失。为了实现重启后数据不丢失,redis提供了两种持久化的方案,一种是RDB快照(Redis Database),一种是AOF(Append Only File)。持久化是redis跟memcache的主要区别之一。

1. RDB

RDB是redis默认的持久化方案(注意如果开启了AOF,优先用AOF)。当满足一定条件的时候,会把当前内存中的数据写入磁盘,生成一个快照文件dump.rdb。redis重启会通过加载dump.rdb文件恢复数据。

1.1 Rdb触发

1 自动触发

a) 配置规则触发。

redis.conf,SNAPSHOTTING,其中定义了触发把数据保存到磁盘的触发频率。如果不需要rdb方案,注释save或者配置成空字符串“”。

1
2
3
save 900 1     #900秒内至少有一个key被修改(包括添加)
save 400 10 #400秒内至少有10个key被修改
save 60 10000 #60秒内至少有10000个key被修改

注意上面的配置是不冲突的,只要满足任意一个都会触发。用lastsave命令可以查看最近一次成功生成快照的时间。Rdb文件位置和目录(默认在安装根目录下):

1
2
3
4
dir ./  #文件路径
dbfilename dump.rdb #文件名称
rdbcompression yes #是否以LZF压缩rdb文件
rdbchechsum yes #开启数据校验
参数 说明
dir rdb文件默认在启动目录下(相对路径) config get dir获取
dbfilename 文件名称
rdbcompression 开启压缩可以节省存储空间,但是会消耗一些CPU的计算时间,默认开启
rdbchecksum 使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能

b) shutdown触发,保证服务器正常关闭。

c) flushall,rdb文件是空的,没什么意义。

2 手动触发

如果我们需要重启服务或者迁移数据,这个时候就需要手动触发快照保存。Redis提供了两条命令:

a) save,在生成快照的时候会阻塞当前redis服务器,redis不能处理其他命令。如果内存中的数据比较多,会造成redis长时间的阻塞。生产环境下不建议使用这个命令。

b) 执行bgsave,执行bgsave时,redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体操作是redis进程执行fork操作创建子线程(copy-on-write),rdb持久化过程由子进程负责,完成后自动结束。它不会记录fork之后产生的数据。阻塞只发生在fork阶段,一般时间很短。

1.2 RDB数据恢复

  1. shutdown持久化
1
2
3
4
5
6
7
8
9
10
11
12
#添加键值
redis> set k1 1
redis> set k2 2
redis> set k3 3
redis> set k4 4
redis> set k5 5
#停止服务器,触发save
redis> shutdown
#备份dump.rdb文件
cp dump.rdb dump.rdb.bak
#启动服务器,数据都在
redis> redis-server redis.conf
  1. 模拟数据丢失
1
2
3
4
5
6
7
#模拟数据丢失,触发save
redis> shutdown
#停止服务器
redis> shutdown
#启动服务器
redis> redis-server redis.conf
#数据丢失
  1. 通过该备份文件恢复数据
1
2
3
4
5
6
7
#停止服务器
redis> shutdown
#重命名备份文件
mv dump.rdb.bak dump.rdb
#启动服务器
redis> redis-server redis.conf
#数据找回

1.3 RDB文件的优劣

一、 优势

1. Rdb是一个非常紧凑(compact)的文件,它保存了redis在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。

2. 生成rdb文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘io操作。

3. Rdb在恢复大数据集时的速度比aof的恢复速度快。

二.劣势

1.rdb方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,频繁执行成本过高。

2.在一定间隔时间做一次备份,所以如果redis意外当掉的话,就会丢失最后一次快照之后的所有修改(数据又丢失)。

​ 如果数据相对来说比较重要,希望将损失降到最小,则可以使用aof方式进行持久化。

2. AOF

Redis默认不开启。aof采用日志的形式来记录每个写操作,并追加文件中。开启后,执行更改redis数据的命令时,就会把命令写入到aof文件中。Redis重启时会根据日志文件的内容把写指令从前到后执行一次以完成数据的恢复工作。

2.1 aof配置

1
2
3
4
# 开关
appendonly no
# 文件名
appendfilename "appendonly.aof"
参数 说明
appendonly Redis默认只开启RDB持久化,开启AOF需要修改为yes
appendfilename 路径也是通过dir参数配置,config get dir

由于操作系统的缓存机制,aof数据并没有真正地写入磁盘,而是进入了系统的硬盘缓存。什么时候把缓冲区的内容写入到aof文件?

参数 说明
appendfsync everysec AOF持久化策略(硬盘缓存到磁盘),默认everysec
no—-表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快,但是不安全
always—-表示每次写入都执行fsync,以保证数据同步到磁盘,效率很低
everysec—-表示每秒执行一次fsync,可能会导致丢失这1s的数据,通常选择everysec,兼顾安全和效率

由于aof持久化是redis不断将写命令记录到aof文件中,随着redis不断的进行,aof文件会越来越大,文件越大,占用服务器内存越大以及aof恢复要求时间越长。例如计数器增加100万次,100万个命令都记录进去了,但是结果只有一个。为了解决这个问题,redis新增了重写机制,当aof文件的大小超过锁设定的阈值时,redis就会启动aof文件的内容压缩,值保留可以恢复数据的最小指令集。可以使用命令bgrewriteaof来重写。Aof文件重写并不是对原文件进行重新整理,而是读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件后去替换原来的aof文件。

1
2
3
# 重写触发机制
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
参数 说明
auto-aof-rewrite-percentage 默认值是100,aof自动重写配置,当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增长到一定大小的时候,Redis能够调用bgrewriteaof对日志文件进行重写,当前AOF文件大小是上次日志重写得到aof文件大小的二倍(设置为100)时,自动启动新的日志重写过程。
auto-aof-rewrite-min-size 默认64M。设置允许重写的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写

问题:重写过程中,AOF文件被更改了怎么办?

当子进程执行aof重写时,主进程需要执行以下三个工作:

(1)处理命令请求;(2)将写命令追加到现有的aof文件中;(3)将写命令追加到aof重写缓存中

参数 说明
no-appendfsync-on-rewrite 在aof重写或者写入rdb文件时,会执行大量IO,此时对于everysec和always的aof模式来说,执行fsync会造成过长时间的阻塞,no-appendfsync-on-rewrite字段设置为默认no。如果对延迟要求很高的应用,这个字段可以设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议修改为yes。Linux默认fsync策略是30秒。可能丢失30秒数据。
aof-load-truncated aof文件可能在尾部是不完整的,当redis启动时,aof文件的数据被载入内存中。重启可能发生在redis所在的主机操作系统宕机后,尤其在ext4文件系统没有加上data=ordered选项,出现这种现象。redis宕机或者异常终止不会造成尾部不完整现象,可以选择让redis退出,或者导入尽可能多的数据。如果选择yes,当截断的aof文件被导入的时候,会自动发布一个log给客户端然后load。如果是no,用户必须手动redis-check-aof修复aof文件才可以。默认为yes。

2.2 AOF数据恢复

重启redis后就会进行aof文件的恢复

2.3 AOF的优劣势

一、 优点:

​ 1. Aof持久化的方法提供了多种的同步频率,即使用默认的同步频率每秒同步一次,redis最多也就丢失1秒的数据而已。

二、缺点

​ 1.对于具有相同数据的redis,aof文件通常会比RDB文件体积更大(rdb存的是数据快照)

​ 2.虽然aof提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能,在高并发的情况下,rdb比aof具有更好的性能保证。

3. 两种方案比较

如果可以忍受一小段时间内数据的丢失,毫无疑问使用rdb是最好的,定时生成rdb快照(snapshot)非常便于进行数据库备份,并且rdb恢复数据集的速度也要比aof恢复的速度要快。否则就是用AOF重写。但是一般情况下建议不要单独使用某一种持久化机制,而是应该两种一起用,在这种情况下,当redis重启的时候会优先加载aof文件来恢复原始的数据,因为在通常情况下aof文件保存的数据集要比RDB文件保存的数据集要完整。


Redis持久化机制
http://www.zivjie.cn/2023/03/04/中间件/redis/Redis持久化机制/
作者
Francis
发布于
2023年3月4日
许可协议