Redis 持久化
1. 持久化机制
Redis 是一款基于内存的非关系型数据库,它会将数据全部存储在内存中。但是如果 Redis 服务器出现某些意外情况,比如宕机或者断电等,那么内存中的数据就会全部丢失。因此必须有一种机制能够保证 Redis 储存的数据不会因故障而丢失,这就是 Redis 的数据持久化机制。
数据的持久化存储是 Redis 的重要特性之一,它能够将内存中的数据保存到本地磁盘中,实现对数据的持久存储。这样即使在服务器发生故障之后,也能通过本地磁盘对数据进行恢复。
Redis 提供了两种持久化机制:
- RDB:又称快照模式
- AOF 日志:也就是追加模式
2. RDB
2.1 RDB 快照模式原理
提示:所谓“快照”就是将内存数据以二进制文件的形式保存起来。
RDB 是 Redis 默认的数据持久化方式,它会将数据库的快照保存在 dump.rdb
这个二进制文件中。
我们知道 Redis 是单线程的,也就说一个线程要同时负责多个客户端套接字的并发读写,以及内存数据结构的逻辑读写。Redis 服务器不仅需要服务线上请求,同时还要备份内存快照。在备份过程中 Redis 必须进行文件 IO 读写,而 IO 操作会严重服务器的性能。那么如何实现既不影响客户端的请求,又实现快照备份操作呢,这时就用到了多进程。
Redis 使用操作系统的多进程 COW 机制(Copy On Write)来实现快照持久化操作:
- RDB 实际上是 Redis 内部的一个定时器事件,它每隔一段固定时间就去检查当前数据发生改变的次数和改变的时间频率,看它们是否满足配置文件中规定的持久化触发条件。当满足条件时,Redis 就会通过操作系统调用 fork() 来创建一个子进程,该子进程与父进程享有相同的地址空间。
- Redis 通过子进程遍历整个内存空间来获取存储的数据,从而完成数据持久化操作。注意,此时的主进程则仍然可以对外提供服务,父子进程之间通过操作系统的 COW 机制实现了数据段分离,从而保证了父子进程之间互不影响。
2.2 RDB 持久化触发策略
RDB 持久化提供了两种触发策略:一种是手动触发,另一种是自动触发。
2.2.1 手动触发策略
手动触发是通过SAVE
命令或者BGSAVE
命令将内存数据保存到磁盘文件中。如下所示:
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> LASTSAVE
(integer) 1611298430
SAVE
命令会阻塞 Redis 服务器进程,直到 dump.rdb 文件创建完毕为止,在这个过程中,服务器不能处理任何的命令请求。
BGSAVE
命令是非阻塞式的,所谓非阻塞式,指的是在该命令执行的过程中,并不影响 Redis 服务器处理客户端的其他请求。这是因为 Redis 服务器会 fork() 一个子进程来进行持久化操作(比如创建新的 dunp.rdb 文件),而父进程则继续处理客户端请求。当子进程处理完后会向父进程发送一个信号,通知它已经处理完毕。此时,父进程会用新的 dump.rdb 文件覆盖掉原来的旧文件。
因为SAVE
命令无需创建子进程,所以执行速度要略快于BGSAVE
命令,但是SAVE
命令是阻塞式的,因此其可用性欠佳,如果在数据量较少的情况下,基本上体会不到两个命令的差别。
LASTSAVE
命令用于查看 BGSAVE
命令是否执行成功。
2.2.2 自动触发策略
自动触发策略,是指 Redis 在指定的时间内,数据发生了多少次变化时,会自动执行BGSAVE
命令。自动触发的条件包含在了 Redis 的配置文件中,即 save <seconds> <changes>
格式的内容。
例如,save 900 1
表示在 900 秒内,至少更新了 1 条数据,那么 Redis 就会自动触发 BGSAVE
命令,将数据保存到硬盘。
每次创建 RDB 文件之后,Redis 服务器为实现自动持久化而设置的时间计数和次数计数就会被清零,并重新开始计数。
2.3 RDB 优缺点
缺点:
- 最后一次持久化的数据可能会丢失——在持久化进行过程中,服务器突然宕机了,这时存储的数据可能并不完整,比如子进程已经生成了 rdb 文件,但是主进程还没来得及用它覆盖掉原来的旧 rdb 文件,这样就把最后一次持久化的数据丢失了。
- 如果数据庞大时使用 fork 子进程的方式还是比较消耗性能
优点:
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高时适合使用
- 还原速度快
3. AOF
AOF(Append Only File) 被称为追加模式,或日志模式,它能够存储 Redis 服务器已经执行过的的命令,并且只记录对内存有过修改的命令,这种数据记录方法,被叫做“增量复制”,其默认存储文件为appendonly.aof
。
3.1 开启 AOF
AOF 机制默认处于未开启状态,可以通过修改 Redis 配置文件开启 AOF,如下所示:
# 修改配置文件:
vim /etc/redis/redis.conf
appendonly yes # 把 no 改为 yes
# 确定存储文件名是否正确
appendfilename "appendonly.aof"
# 重启服务:
sudo /etc/init.d/redis-server restart
3.2 AOF 持久化机制
每当有一个修改数据库的命令被执行时,服务器就将命令写入到 appendonly.aof 文件中,该文件存储了服务器执行过的所有修改命令,因此,只要服务器重新执行一次 .aof 文件,就可以实现还原数据的目的,这个过程称之为命令重演。
重写机制:Redis 在长期运行的过程中,aof 文件会越变越长。如果机器宕机重启,“重演”整个 aof 文件会非常耗时,导致长时间 Redis 无法对外提供服务,因此就需要对 aof 文件做一下“瘦身”。故而,Redis 提供了 AOF 重写机制,执行BGREWRITEAOF
命令即可。
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started
新的 aof 文件记录的数据库数据和原 aof 文件记录的数据库数据完全一致;
新的 aof 文件会使用尽可能少的命令来记录数据库数据,因此新的 aof 文件的体积会小很多;
AOF 重写期间,服务器不会被阻塞,它可以正常处理客户端发送的命令。
原有 aof 文件 重写后 aof 文件 select 0 SELECT 0 sadd myset Jack SADD myset Jack Helen JJ Lisa sadd myset Helen SET msg 'hello tarena' sadd myset JJ RPUSH num 4 6 8 sadd myset Lisa INCR number INCR number DEL number SET message 'www.baidu.com' SET message 'www.biancheng.net' RPUSH num 2 4 6 RPUSH num 8 LPOP num
通过配置文件也可将 AOF 重写机制改为自动触发:
# 默认配置项
auto-aof-rewrite-percentage 100 # 触发重写所需要的 aof 文件体积百分比
auto-aof-rewrite-min-size 64mb # 表示触发 AOF 重写的最小文件体积,大于或等于 64MB 自动触发。
该配置项表示:有当 aof 文件的增量大于 100% 时进行重写,也就是大一倍。
比如,第一次重写时文件大小为 64M,那么第二次触发重写的体积为 128M,第三次重写为 256M,以此类推。如果将百分比值设置为 0 就表示关闭 AOF 自动重写功能。
3.3 AOF 策略配置
在上述介绍写入机制的过程中,如果遇到宕机前,缓存内的数据未能写入到磁盘中,那么数据仍然会有丢失的风险。服务器宕机时,丢失命令的数量,取决于命令被写入磁盘的时间,越早地把命令写入到磁盘中,发生意外时丢失的数据就会越少,否则越多。
Redis 为数据的安全性考虑,同样为 AOF 持久化提供了策略配置,即配置文件中的 appendfsync
选项,其可选值为:
附:Linux 系统的 fsync() 函数可以将指定文件的内容从内核缓存刷到硬盘中,由于是 fsync 是磁盘 IO 操作,所以它很慢!
- Always:服务器每写入一个命令,就调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,也不会丢失任何已经成功执行的命令数据,但是其执行速度较慢;
- Everysec(默认):服务器每一秒调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据,通常都使用它作为 AOF 配置策略;
- No:服务器不主动调用 fsync 函数,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的,所以这种策略,不确定性较大。
3.4 AOF 数据恢复
AOF 的备份机制和性能虽然和 RDB 不同,但是备份和恢复的操作同 RDB 一样,都是拷贝备份文件,需要恢复时再拷贝到 Redis 工作目录下,启动系统即加载。
通过 AOF 备份恢复数据的流程:
- 修改默认的 appendonly no 为 yes
- 将有数据的 .aof 文件复制一份保存到 Redis 根目录 (config get dir)
- 重启 redis 即可
如遇 .aof 文件损坏,可通过/usr/local/bin/redis-check-aof--fix appendonly.aof
进行修复。
3.5 AOF 优缺点
RDB 持久化 | AOF 持久化 |
---|---|
全量备份,一次保存整个数据库 | 增量备份,一次只保存一个修改数据库的命令 |
每次执行持久化操作的间隔时间较长 | 保存的间隔默认为一秒钟(Everysec) |
数据保存为二进制格式,其还原速度快 | 使用文本格式还原数据,所以数据还原速度一般 |
执行 SAVE 命令时会阻塞服务器,但手动或者自动触发的 BGSAVE 不会阻塞服务器 | AOF 持久化无论何时都不会阻塞服务器 |
4. 同时开启 RDB 与 AOF 时
AOF 和 RDB 同时开启时,redis 重启时默认取 AOF 的数据(数据不会存在丢失)。
5. 数据备份与恢复
通常使用 RDB 方式来备份 Redis 数据库。
- 备份:使用
SAVE
或BGSAVE
生成 dump.rdb 文件 - 恢复:将 dump.rdb 文件拷贝至 redis 安装目录(可通过
CONFIG GET dir
来获取)即可