redis 持久化原理解析
1. 前言
本文将先说明持久化、主存复制(及读写分离)、哨兵、以及集群几种技术分别解决了Redis高可用的什么问题;
然后详细介绍Redis的持久化技术,主要是RDB和AOF两种持久化方案;在介绍RDB和AOF方案时,不仅介绍其作用及操作方法,同时介绍持久化实现的一些原理细节及需要注意的问题。
最后,介绍在实际使用中,持久化方案的选择,以及经常遇到的问题等。
1.1 redis 如何支持服务高可用
在介绍Redis高可用之前,先说明在Redis的语境中高可用的含义。
我们知道,在Web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999% 等等)。但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务(主存分离、快速容灾技术)还需要考虑数据容量的扩展,数据安全不会丢失等。
在Redis中,实现高可用技术主要包括持久化、主存复制、哨兵和集群,下面分别说明他们的作用以及解决了什么问题。
- 持久化:持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
- 主存复制:复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复(
读写分离
)。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制
。 - 哨兵:在复制的基础上,哨兵实现了自动化的故障转移。缺陷:
写操作无法负载均衡;存储能力受单机限制
- 集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受单机限制的问题,实现了较为完善的高可用方案,
不支持故障恢复以及自动转移
2. 夯实基础
2.1 什么是持久化
Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据永久丢失,需要定期将Redis中的数据以某种形式(数据/命令)从内存保存到磁盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置;
2.2 持久化分类
1)RDB(Redisu Database)
RDB 持久化: 是指在指定的时间间隔内将内存中的数据集快照写入磁盘
,也就是 snapshot内存快照
,它恢复时再将磁盘快照文件(dump.rdb
)直接读回到内存。
实现类似照片记录效果的方式,就是把某一时刻的数据和状态以文件的形式写到磁盘上,也就是快照。这样一来即使故障宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。
这个快照文件就称为RDB文件(dump.rdb
),其中,RDB就是Redis DataBase的缩写。
2)AOF(Append Only file)
AOF持久化: 是指以日志的形式来记录每个写操作
,将Redis所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据。
换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次已完成数据的恢复工具。
默认情况下,redis是没有开启AOF(append of file)的。开启AOF功能需要设置配置:
appendonly yes
AOF 保存的是 appendonly.aof
文件
3)RDB-AOF 混合持久化
疑问:rdb vs aof 可否共存?如果共存以哪种方式为准?
下面是配置文件的说明
数据恢复顺序与加载流程:在同时开启 rdb和aof 持久化时,重启时只会加载aof文件,不会加载rdb文件。
4)纯缓存模式
同时关闭 RDB+AOF
// 禁用rdb
save ""
// 禁用aof
appendonly no
注意在禁用rdb和aof后仍然可以使用持久化命令生成对应的持久化文件。
- 禁用rdb的模式下,仍然可以使用命令
save
bgsave
生成rdb文件。 - 禁用aof的模式下,仍然可以使用
bgrewriteaof
生成aof文件。
2.3 RDB 持久化
RDB保存到磁盘的文件叫dump.rdb
。
1)持久化流程
RDB 持久化是指在指定的时间间隔内将内存中的数据快照写入磁盘,实际操作过程是 fork 一个子进程,先将数据写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
第一步: 配置文件说明
redis 6.0.16以下配置
redis 6.2 以及redis 7
第二步: 2) 操作说明
操作主要分为手动触发
和自动触发
两种方式。
方式一:自动触发
Redus 7 版本 按照 redis.conf 里配置的 save <seconds> <changes>
比如 5秒修改2次
第三步:如何恢复
将备份文件(dump.rdb
) 移动到redis安装目录并启动服务器即可。
验证一:备份成功后故意使用flushdb
清空redis,看看是否可以恢复数据。
验证二:物理恢复,服务和备份分机隔离
。
备注:不可以把备份文件dump.rdb和生产redis服务器放在同一台机器,必须分开各自存储,以防生产机物理损坏后备份文件也挂了。
方式二:手动触发
redis 提供了两个命令来支持生成rdb文件,分别是 save
和 bgsave
(1)save 同步阻塞生成rdb文件 主要是在主程序执行,会阻塞当前redis服务器,直到持久化工作完成,执行save命令期间,redis不能处理其它命令,线上禁止使用
。
案例说明:
(2)bgsave 异步生成rdb文件(默认):redis会在后台异步快照操作,不阻塞
快照,同时还可以响应客户端请求,该触发方式会 fork一个子进程,由子进程复制持久化过程。
fork 是什么?
在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,尽量避免膨胀。
案例说明:
lastsave 可以通过lastsave命令获取最后一次成功执行快照的时间。
2)RDB 持久化优劣势
优势:
- RDB是一个紧凑压缩的二进制文件,效率高,Redis在某个时间点上的数据 快照。非常适用于备份,全量复制等场景。
- 与 AOF 格式的文件相比,RDB 文件可以更快的重启。
- RDB 对灾难恢复非常有用,它是一个紧凑的文件,可以更快的传输到远程服务器进行 Redis 服务恢复,性能最大化,fork出子进程来完成写操作,让主进程继续处理命令,所以是IO最大化(使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证了redis的高性能) ;
- 如果数据集偏大,RDB的启动效率会比AOF更高。
劣势:
- RDB方式数据没无法做到实时持久化,紧急情况丢失的数据比AOF多
- bgsave每次执行都会fork新的进程,牺牲一部分cpu
- Reids不同版本的RDB文件不统一,容易造成不兼容
数据丢失的案例:
- 正常录入数据
kill -9
故意模拟意外宕机- redis重启恢复后,查看数据是否丢失
3)哪些情况会触发RDB快照
4)如何禁用快照
方式一:使用命令设置保存rdb规则的方法:redis-cli config set save ""
方式二:配置文件,快照禁用
5)小总结
2.4 AOF持久化
1)持久化流程
命令写入 (append)、文件同步(sync)、文件重写(rewrite)、重启加载 (load)。
2)缓存区三种写回策略
# 每次有新命令追加到 AOF 文件时就执行一次同步 :非常慢,也非常安全
$ always
# 每秒同步一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据
# 推荐(并且也是默认)的措施为每秒同步一次, 这种策略可以兼顾速度和安全性
$ everysec
# 从不同步:将数据交给操作系统来处理。更快,也更不安全的选择
$ no
策略一:同步写回Always
:每个写命令执行完立刻同步的将命令写回磁盘。
策略二:每秒写回everysec
:每个写命令执行完,只是先把日志写到 AOF文件的内存缓冲区,每隔一秒把缓冲区的内容写入磁盘。
策略三:操作系统控制写回no
:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区的内容写入磁盘。
具体配置如下
3)AOF 持久化优劣势
优势:
- AOF 持久化保存的数据更加完整,AOF 提供了三种保存策略:每次操作保存、每秒钟保存一次、跟随系统的持久化策略保存,其中每秒保存一次,从数据的安全性和性能两方面考虑是一个折中的选择,也是 AOF 默认的策略,即使发生了意外情况,最多只会丢失 1s 钟的数据;
- AOF 采用的是命令追加的写入方式,所以不会出现文件损坏的问题,即使由于某些意外原因,导致了最后操作的持久化数据写入了一半,也可以通过 redis-check-aof 工具轻松的修复;
- AOF 持久化文件,非常容易理解和解析,它是把所有 Redis 键值操作命令,以文件的方式存入了磁盘。即使不小心使用 flushall 命令删除了所有键值信息,只要使用 AOF 文件,删除最后的 flushall 命令,重启 Redis 即可恢复之前误删的数据。
劣势:
- 相同数据集的数据而言,aof文件要远大于rdb文件,恢复速度慢于rdb
- 在 Redis 负载比较高的情况下,RDB 比 AOF 性能更好;
- RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF 文件中,因此从理论上说,RDB 比 AOF 更健壮。
4)AOF 重写机制
AOF 是存放每条写命令的,所以会不断变大,达到一定的时候,AOF做rewrite操作,会重新生成一个新的AOF文件。
文件越大,占用服务器内存越大以及 AOF 恢复要求时间越长。
为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的峰值时,Redis就会自动启动AOF文件的内容压缩,
简单说就是将对一个数据的多个命令的最终结束结果储存到AOF文件中。
重写 rewrite的作用
- 降低磁盘占用率
- 提高持久化效率,提高IO性能
- 降低恢复用时
重写规则
- 进程内已超时的数据不写入
- 忽略无效指令,只保留最终结果,例如 set name 1, set name 2,只会保存第二条
- 多条命令合并为1条,例如 del key1,del key2会被保存为 del key1 key2
手动重写
自动重写
- 在重写开始前,redis会创建一个“重写子进程”,这个子进程会读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。
- 与此同时,主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。
- 当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中
- 当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中
- 重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
5)小总结
2.5 RDB+AOF 混合持久化
RDB和AOF持久化各有优缺点,RDB会导致一段时间内的数据丢失,AOF文件会越来越大,会影响Redis的启动速度,为了同时兼顾RDB,AOF的优点,Redis在4.0版本之后
提供了混合持久化
方式。
AOF 重写时会把 Redis 的持久化数据,以 RDB 的格式写入到 AOF 文件的开头,之后的数据再以 AOF 的格式化追加的文件的末尾,如下图所示。
1)开启混合持久化
开启混合 将no改为yes即可
2)优缺点
优点:混合持久化结合了 RDB 和 AOF 持久化的优点,开头为 RDB 的格式,使得 Redis 可以更快的启动,同时结合 AOF 的优点,有减低了大量数据丢失的风险。
缺点:AOF 文件中添加了 RDB 格式的内容,会使得 AOF 文件的可读性会很差,不容易阅读;
如果开启混合持久化,就必须使用 Redis 4.0 以及之后版本。
3)小总结
使用混合持久化的时候可以根据自身业务选择关闭RDB或者AOF,或者关闭持久化。
二者选择的标准,就是看是否愿意牺牲一些性能,换取更高的缓存一致性(AOF),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行 save 的时候,再做备份(RDB)。
注: 未来 Redis 可能会将 AOF 和 RDB 整合成单个持久化模型.