Redis将数据存储在内存当中,为了防止数据丢失与服务重启时能够恢复数据,Redis支持数据的持久化,这主要分为两种方式,即RDB与AOF.
RDB
RDB持久化是把当前进程数据生成快照保存到磁盘上的过程,由于是某一时刻的快照,那么快照中的值要早于或者等于内存中的值。
生成的rdb文件的名称以及存储位置由redis.conf中的dbfilename和dir两个参数控制,默认生成的rdb文件是dump.rdb。
触发方式
手动触发
在redis客户端执行save与bgsave命令。但两种命令存在区别:
- save会使用redis主进程进行持久化,会阻塞redis服务,线上环境不建议使用。
- bgsave会fork一个子进程,使用子进程进行持久化
。只有在fork子进程时会短暂阻塞主进程,fork操作完成后主进程可以正常执行主进程。
自动触发
所有的自动触发都是使用bgsave操作。
- redis.conf中配置save m n,即在m秒内有n次修改时,自动触发bgsave生成rdb文件;
- 主从复制时,从节点要从主节点进行全量复制时也会触发bgsave操作,生成当时的快照发送到从节点;
- 执行debug reload命令重新加载redis时也会触发bgsave操作;
- 默认情况下执行shutdown命令时,如果没有开启aof持久化,那么也会触发bgsave操作;
关闭持久化
- 执行以下命令(redis-cli):config set save “”
- 修改配置文件
// 打开该行注释
save ""
// 注释掉以下内容
# save 900 1
# save 300 10
# save 60 10000
持久化流程
具体流程如下:
- redis客户端执行bgsave命令或者自动触发bgsave命令;
- 主进程判断当前是否已经存在正在执行的子进程,如果存在,那么主进程直接返回;
- 如果不存在正在执行的子进程,那么就fork一个新的子进程进行持久化数据,fork过程是阻塞的,fork操作完成后主进程即可执行其他操作;
- 子进程先将数据写入到临时的rdb文件中,待快照数据写入完成后再原子替换旧的rdb文件;
- 同时发送信号给主进程,通知主进程rdb持久化完成,主进程更新相关的统计信息(info Persitence下的rdb_*相关选项)。同时发送信号给主进程,通知主进程rdb持久化完成,主进程更新相关的统计信息(info Persitence下的rdb_*相关选项)。
RDB持久化方式的优缺点
优点
- RDB文件是某个时间节点的快照,默认使用LZF算法进行压缩,压缩后的文件体积远远小于内存大小,适用于备份、全量复制等场景;
- Redis加载RDB文件恢复数据要远远快于AOF方式;
缺点
- RDB方式实时性不够,无法做到秒级的持久化;
- 每次调用bgsave都需要fork子进程,fork子进程属于重量级操作,频繁执行成本较高;
- RDB文件是二进制的,没有可读性,AOF文件在了解其结构的情况下可以手动修改或者补全;
AOF
aof方式持久化是使用文本协议将每次的**写命令(增删改)**记录到aof文件中,经过文件重写后记录最终的数据生成命令,在redis启动时,通过执行aof文件中的命令恢复数据。
aof方式主要解决了数据实时性持久化的问题,aof方式对于兼顾数据安全性和性能非常有帮助。
开启AOF
- 客户端命令行
# 开启aof
config set appendonly yes
# 关闭aof
config set appendonly no
- 修改配置文件
# 开启aof
appendonly true
# aof文件名称
appendfilename "appendonly.aof"
# aof文件存储位置
dir ./
AOF持久化流程
- append
aof文件只记录写命令,不记录读命令,当服务端接收到写命令后,redis会将命令写入到aof缓冲区中,之所以写入缓冲区而不直接写入aof文件中是因为如果每次都将命令直接写入到文件中,那么redis的性能将完全取决于硬盘的读写能力,这与redis性能至上的理念不符,另外,写入缓冲区中也便于使用不同的同步策略。 - sync
文件同步,即将aof缓冲区中的命令同步到aof文件中,redis提供三种策略以供选择,由参数appendfsync控制,三种策略分别是:
always: 表示命令append到缓冲区以后调用系统fsync操作同步到aof文件中,fsync操作完成后主线程返回;
no: 表示命令写入aof缓冲区后调用操作系统write操作,不对aof文件做fsync同步,同步到硬盘操作由操作系统负责,通常同步周期最长30秒;
everysec: 表示命令写入aof缓冲区后调用操作系统write操作,write操作完成后主线程返回,由专门的线程每秒去进行fsync同步文件操作
默认使用everysec,兼顾性能和安全性,很显然,使用always时每次都要等同步完成后才能返回,这个性能是很低的;同理使用no时,虽然不用每次都同步aof文件,但是同步操作周期不可控,数据安全性得不到保障,因此还是使用默认的everysec兼顾安全性和性能,每一秒同步一次,也就是在突发状况下最多丢失1秒的数据。
- 重写(rewrite)(也即简化aof文件)
随着写命令越来越多,aof文件的体积也越来越大,此时就需要重写机制来按照特定的机制清除或者合并命令从而达到减小文件体积,便于redis重启加载的目的。
重写机制
重写机制
- 进程内已经过期的数据不再写入文件;
- 只保存最终数据的写入命令
- 多条写命令合并为一条命令
触发
- 手动触发
手动执行**bgrewriteaof
**命令即可触发aof重写 - 自动触发
修改配置文件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-min-size: 表示触发aof重写时aof文件的最小体积,默认64m
auto-aof-rewrite-percentage: 表示当前aof文件空间和上一次重写后aof文件空间的比值,默认是aof文件体积翻倍时触发重写,计算方法:auto-aof-rewrite-percentage =(当前aof文件体积 - 上次重写后aof文件体积)/ 上次重写后aof文件体积 * 100%
- 自动触发的触发条件
(当前aof文件体积 > auto-aof-rewrite-min-size) && (auto-aof-rewrite-percentage的计算值 > 配置文件中配置的auto-aof-rewrite-percentage值)
重写流程
- 手动或者自动触发文件重写后主进程需要先判断当前是否有子进程存在,如果存在则直接返回,不存在则fork子进程;
- fork操作完成后,主进程即可响应其他命令,在子进程生成新的aof文件过程中,主进程仍然维持原来的流程以保证原有aof机制的正确性;
- 在子进程生成新的aof文件过程中主进程执行的新命令同时会被写入到aof重写缓冲区中,当新aof文件生成后再将这一部分命令写入到新aof文件中,防止数据丢失;
- 子进程根据内存快照,根据重写规则生成新的aof文件,每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为32MB,防止单次刷盘数据过多造成硬盘阻塞;
- 父进程把aof重写缓冲区的数据写入到新的aof文件中;
- 使用新aof文件替换旧的aof文件并发送信号给主进程表示重写完成。
优缺点
优点
- 数据安全性高
- aof文件可读性强,便于灾难性恢复
缺点
- aof文件体积庞大不利于传输
- 数据恢复速度较慢