Redis持久化

一、持久化简介

因为Redis是内存数据库,它将自己的数据库状态储存在内存里面,所以如果不想办法将储存在内存中的数据库状态保存到磁盘里面,那么一旦服务器进程退出,服务器中的数据库状态也会消失不见。

因此Redis 提供了两种持久化方案,RDB (Redis DataBase)和 AOF (Append Only File)。

二、RDB持久化

RDB 是 Redis 默认的持久化方案。RDB持久化可以手动执行也可以根据服务器配置选项定期执行。该功能会将在某个时间点上的数据库状态保存到一个.rdb文件。Redis 重启会通过加载.rdb文件恢复数据。

2.1 RDB手动备份恢复

有两个redis命令可以用于生成rdb文件:

  • save:save命令会阻塞redis服务器进程,直到rdb文件创建完成为止,在服务器进程阻塞期间不能处理任何命令请求;

  • bgsave:bgsave命令会派生出一个子进程,由子进程负责创建rdb文件,父进程继续处理redis命令。

rdb文件的数据恢复工作是在redis启动时自动完成的,没有特殊命令来手动进行恢复工作,值得注意的是由于AOF的更新频率通常会比RDB更新频率高,因此如果服务器开启了AOF持久化那么redis优先使用AOF恢复数据,只有在AOF持久化关闭时才使用RDB恢复数据。

# 阻塞主进程的持久化
127.0.0.1:6379> save
OK
# 使用子进程持久化
127.0.0.1:6379> BGSAVE
Background saving started
# 执行任意一个命令就会生成/var/lib/redis/dump.rdb 文件

# rdb文件恢复
# 查看rdb文件存放位置
127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/var/lib/redis"
# 将需要恢复的rdb文件放在/var/lib/redis下
# 重启redis(注意:不要使用service redis-server restart/stop/start重启,否则出现莫名其妙的错误,rdb无法恢复)
redis-cli shutdown
sudo redis-server /etc/redis/redis.conf
# 登录redis-cli就会看到恢复的数据

2.2 RDB配置

/etc/redis/redis.conf 文件中

save 900 1  # 时间策略,服务器在900秒之内,对数据库进行了至少1次修改。
save 300 10  # 时间策略,服务器在300秒之内,对数据库进行了至少10次修改。
save 60 10000  # 时间策略,服务器在60秒之内,对数据库进行了至少1000次修改。
dbfilename dump.rdb   #文件名称
dir /var/lib/redis   #文件保存路径 
stop-writes-on-bgsave-error yes   # 如果持久化出错,主进程是否停止写入 
rdbcompression yes    # 是否压缩 
rdbchecksum yes     # 导入时是否检查 

# 通过save 300 10次略,我们可以在5分钟内插入10个数据,到了五分钟发现的确生成了新的dump.rdb文件,说明配置生效

那么为什么需要配置这么多条规则呢?因为Redis每个时段的读写请求肯定不是均衡的,为了平衡性能与数据安全,我们可以自由定制什么情况下触发备份。所以这里就是根据自身Redis写入情况来进行合理配置。

2.3 RDB优缺点

优点

  • 适合大规模的数据恢复。

  • 如果业务对数据完整性和一致性要求不高,RDB是很好的选择。

缺点:

  • 数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。

  • 备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时总占用内存是原来的两倍),最后再将临时文件替换之前的备份文件。所以Redis 的持久化和数据的恢复要选择在夜深人静的时候执行是比较合理的。

三、AOF持久化

Redis 默认不开启。它的出现是为了弥补RDB的不足(数据的不一致性),所以它采用日志的形式来记录每个写操作,并追加到文件中。Redis 重启的会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

3.1 AOF持久化步骤

  1. 命令追加:在AOF模式打开的情况下,服务器每执行一次写命令就会以协议格式将执行的写命令追加到aof_buf缓冲区的末尾;

  2. AOF文件的写入和同步:Redis每执行完一次事件循环,就要考虑要不要将缓冲区的数据写入AOF文件,写入同步策略有配置文件的appendfsync决定:appendfsync的值有三个

    1. always:将缓冲区所有内容写入并同步AOF文件;

    2. everysec(默认):将缓冲区内容写入AOF文件,如果上次同步AOF文件的时间与现在间隔超过1秒钟,那么在此对AOF文件进行同步,并且这个同步操作是由一个线程专门执行的;

    3. no:将缓冲区内容写入文件,不对AOF进行同步,何时同步由操作系统来决定。

tips:
为了提高文件的写入效率,在现代操作系统中,当用户调用write函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满、或者超过了指定的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。这种做法虽然提高了效率,但也为写入数据带来了安全问题,因为如果计算机发生停机,那么保存在内存缓冲区里面的写入数据将会丢失。为此,系统提供了fsync和fdatasync两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性。

3.2 AOF重写机制

因为AOF备份的策略是保存所有的写命令,当写命令不断增加时,AOF文件会越来越大,可能会影响系统性能和恢复数据的性能。为了解决这个问题,Redis提供了AOF文件重写(rewrite)功能。通过该功能,Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库状态相同,但新AOF文件不会包含任何浪费空间的冗余命令,所以新AOF文件的体积通常会比旧AOF文件的体积要小得多。

那么它是如何实现的呢?虽然名字叫做AOF重写,但是新文件并不会读取并分析旧的AOF文件,而是通过读取当前数据库的状态来实现的。过程就是首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是AOF重写功能的实现原理。

数据不一致的处理

Redis使用一个子进程来处理AOF的重写,这样会导致数据不一致的问题,比如当开始重写的时候数据库只有key1,在重写过程中有增加了key2,那么重写完后AOF中只有key1,就导致了数据的不一致。为了解决这种数据不一致问题,Redis服务器设置了一个AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令之后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区。

当子进程完成AOF重写工作之后,它会向父进程发送一个信号,父进程在接到该信号之后,会调用一个信号处理函数,并执行以下工作:

  • 将AOF重写缓冲区中的所有内容写入到新AOF文件中,这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致。

  • 对新的AOF文件进行改名,原子地(atomic)覆盖现有的AOF文件,完成新旧两个AOF文件的替换。这个信号处理函数执行完毕之后,父进程就可以继续像往常一样接受命令请求了。

在整个AOF后台重写过程中,只有信号处理函数执行时会对服务器进程(父进程)造成阻塞,在其他时候,AOF后台重写都不会阻塞父进程,这将AOF重写对服务器性能造成的影响降到了最低。

3.3 AOF配置和恢复

/etc/redis/redis.conf 文件中

appendonly yes  # yes表示开启AOF持久化
appendfilename "appendonly.aof" 
appendfsync everysec # 数据写入同步的策略(everysec、always、no)
#设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no
no-appendfsync-on-rewrite no 
#当前AOF文件大小是上次日志重写得到AOF文件大小的二倍时,自动启动新的日志重写过程。
auto-aof-rewrite-percentage 100
#当前AOF文件启动新的日志重写过程的最小值,避免刚刚启动Reids时由于文件尺寸较小导致频繁的重写。
auto-aof-rewrite-min-size 64mb

恢复数据:

# 配置完后重启redis,写入几条数据,发现生成了aof文件
# 先将aof文件移动到其他目录,然后清空所有数据,再移动回来,重启redis后发现数据恢复了。

appendonly.aof其实就是文本文件,所以完全可以手动修改aof文件来恢复成指定的数据:

# file appendonly.aof 
appendonly.aof: ASCII text, with CRLF line terminators
# cat appendonly.aof 
*2
$6
SELECT
$1
0
*3
$3
......此处省略N行
set
$5
name4
$1
4

3.4 AOF优缺点

优点:

数据的完整性和一致性更高

缺点:

因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢。

四、总结

  1. Redis 默认开启RDB持久化方式,在指定的时间间隔内,执行指定次数的写操作,则将内存中的数据写入到磁盘中。

  2. RDB 持久化适合大规模的数据恢复但它的数据一致性和完整性较差。

  3. Redis 需要手动开启AOF持久化方式,默认是每秒将写操作日志追加到AOF文件中。

  4. AOF 的数据完整性比RDB高,但记录内容多了,会影响数据恢复的效率。

  5. Redis 针对 AOF文件大的问题,提供重写的瘦身机制。

  6. 若只打算用Redis 做缓存,可以关闭持久化。

  7. 若打算使用Redis 的持久化。建议RDB和AOF都开启。其实RDB更适合做数据的备份,留一后手。AOF出问题了,还有RDB。

问题

  1. RDB和AOF持久化后的文件存储在哪?

RDB文件存储在/var/lib/redis/dump.rdb,实际位置取决于配置文件/etc/redis/redis.conf中的dir /var/lib/redis,也可以在redis-cli中使用命令config get dir获取。

  1. AOF持久化开启后,是否只是记录开启时间点之后的写操作,那之前的数据如何保证备份呢?

AOF重写时会以当前数据库为依据生成所有写入语句。

Last updated