Redis 分别提供了 RDB 和 AOF 两种持久化机制:
- RDB 将数据库的快照(snapshot)以二进制的方式保存到磁盘中。
- AOF 则以协议文本的方式,将所有对数据库进行过写入的命令(及其参数)记录到 AOF 文件,以此达到记录数据库状态的目的。
RDB
a. 什么是RDB
和 MySQL 中的 mysqldump
差不多一个道理。
b. 什么情况下会触发 RDB
第一种情况,主动执行 save
命令
(同步,阻塞 ,就是save
命令执行完毕后才能执行后续的其他命令操作)
阻塞
保存 RDB 文件的策略
每次创建新的文件,并且替换原来旧文件(假如存在旧的文件)
第二种情况,主动执行 bgsave
命令 (异步,非阻塞 )
- 文件策略和
save
相同
第三种情况,自动触发
自动触发,就是通过对 Redis 的配置文件重相关选项的修改,当达到某个配置好的条件后,自动生成 RDB 文件
,其内部使用的是 bgsave
命令。
配置文件中相关选项的默认值如下表:
配置 | seconds | changes | 含义 |
---|---|---|---|
save | 900 | 1 | 每隔 900 秒检查一次,假如至少有 1 条数据改变,就生成新的 RDB 文件 |
save | 300 | 10 | 每隔 300 秒检查一次,假如至少有 10 条数据改变,就生成新的 RDB 文件 |
save | 60 | 10000 | 每隔 60 秒检查一次,假如至少有 10000 条数据改变,就生成新的 RDB 文件 |
每次检查都会建立一个新的检查点,以便用于下次检查作为参考信息。
关于 RDB 文件的配置信息
默认文件名
dbfilename dump.rdb
默认文件保存位置
dir ./
假如
bgsave
执行中发生错误,是否停止写入,默认是yes
, 表示假如出错,就停止写入。
stop-writes-on-bgsave-error yes
是否使用压缩|
rdbcompression yes
是否进行数据的校验
rdbchecksum yes
建议的最佳配置
关闭自动生成 RDB 文件
在配置文件中注释掉如下内容
#save 900 1
#save 300 10
#save 60 10000
使用不同端口号进行区分,因为,有可能会在同一台主机上开启多个 Redis 实例。
防止多个实例产生的数据信息写到一个文件中。
dbfilename dump-${port}.rdb
指定一个大硬盘的路径
dir /redis_data
假如出现错误,停止继续写入
stop-writes-on-bgsave-error yes
采用压缩
rdbcompression yes
进行校验
rdbchecksum yes
实验
进入centos的docker容器
安装所需包和模块
yum install epel-release
yum install -y redis
yum install -y supervisor
查看redis安装时所有文件
rpm -ql redis
可发现其中有/usr/bin/redis-server
注意:可用
/usr/bin/redis-server
命令启动服,但用此命令启动,会运行在前台
因为会占用终端,所以采用下文supervisor
的方式启动redis服务
补充:可用
rpm -qc redis
查看所有的配置文件、rpm -qa redis
或rpm -qa |grep redis
查找rpm安装所有包中过滤redis包
创建文件夹
mkdir /etc/redis
打开配置文件
vi /etc/6379.conf
-
注释这三行
-
改写这行
创建配置文件/etc/supervisord.d/redis.ini
vi /etc/supervisord.d/redis.ini
文件内容详解:
[program:qfcmdb]
;执行的命令
command=/usr/bin/redis-server /etc/redis/6379.conf
priority=999 ; 优先级(越小越优先)
autostart=true ; supervisord启动时,该程序也启动
autorestart=true ; 异常退出时,自动启动
startsecs=10 ; 启动后持续10s后未发生异常,才表示启动成功
startretries=3 ; 异常后,自动重启次数
exitcodes=0,2 ; exit异常抛出的是0、2时才认为是异常
stopsignal=QUIT ; 杀进程的信号
; 在程序发送stopignal后,等待操作系统将SIGCHLD返回给supervisord的秒数。
; 如果在supervisord从进程接收到SIGCHLD之前经过了这个秒数,
; supervisord将尝试用最终的SIGKILL杀死它
stopwaitsecs=1
user=root ; 设置启动该程序的用户
log_stdout=true ; 如果为True,则记录程序日志
log_stderr=false ; 如果为True,则记录程序错误日志
logfile=/var/log/6379.log ; 程序日志路径
logfile_maxbytes=1MB ; 日志文件最大大小
logfile_backups=3 ; 日志文件最大数量
[include]
files = relative/directory/*.ini
/etc/supervisord.d/redis.ini
[program:redis-6379]
command=/usr/bin/redis-server /etc/redis/6379.conf
priority=999
autostart=true
autorestart=true
startsecs=10
startretries=3
exitcodes=0,2
stopsignal=QUIT
stopwaitsecs=1
user=root
log_stdout=true
log_stderr=false
logfile=/var/log/6379.log
logfile_maxbytes=1MB
logfile_backups=3
查看配置文件
supervisor配置文件位置
vi /etc/supervisord.conf
/etc
下已修改的文件结构
- supervisord.conf 文件和 supervisord.d文件夹
其中supervisord.d
文件夹中有一个自定义的任意
的.ini
的文件
(此处自定义命名为redis.ini
文件)
- redis文件夹
(其中有一个自定义
的任意的以.conf结尾
的文件,此处命名为:6379.conf
文件)
启动supervisor
supervisord
报错信息
由于 已经以/usr/bin/redis-server起了一个redis服务,所以,supervisord一直无法启动,先需要kill掉这两个进程,然后用supervisor重启服务即可
-
此时,再查看,可发现redis服务已启动
手动触发生成二进制文件
注释了三个save,所以需要手动去save后触发生成.rdb的文件
持久化存储
重启redis后,可发现set的name依旧存在,因此实现了持久化存储
修改配置文件
vi /etc/redis/6379.conf
-
修改name,触发保存
- 查看配置文件中定义的保存文件
cat /var/lib/redis/appendonly-6379.aof
AOF
什么是 AOF
AOF 文件保存了 Redis 的数据库状态, 而文件里面包含的都是符合 Redis 通讯协议格式的命令文本。
AOF 保存的模式
Redis 目前支持三种 AOF 保存模式,它们分别是:
-
AOF_FSYNC_NO
:不保存。 -
AOF_FSYNC_EVERYSEC
:每一秒钟保存一次。(生产中一般选这种) -
AOF_FSYNC_ALWAYS
:每执行一个命令保存一次
不保存
在这种模式下, SAVE 只会在以下任意一种情况中被执行:
Redis 被关闭
AOF 功能被关闭
系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行)
这三种情况下的 SAVE 操作都会引起 Redis 主进程阻塞。
每执行一个命令保存一次
在这种模式下,每次执行完一个命令之后, WRITE 和 SAVE 都会被执行。
另外,因为 SAVE 是由 Redis 主进程执行的,所以在 SAVE 执行期间,主进程会被阻塞,不能接受命令请求。
AOF 三种保存模式的比较
因为阻塞操作会让 Redis 主进程无法持续处理请求, 所以一般说来, 阻塞操作执行得越少、完成得越快, Redis 的性能就越好。
模式 1 的保存操作只会在AOF 关闭或 Redis 关闭时执行, 或者由操作系统触发, 在一般情况下, 这种模式只需要为写入阻塞, 因此它的写入性能要比后面两种模式要高, 当然, 这种性能的提高是以降低安全性为代价的: 在这种模式下, 如果运行的中途发生停机, 那么丢失数据的数量由操作系统的缓存冲洗策略决定。
模式 2 在性能方面要优于模式 3 , 并且在通常情况下, 这种模式最多丢失不多于 2 秒的数据, 所以它的安全性要高于模式 1 , 这是一种兼顾性能和安全性的保存方案。
模式 3 的安全性是最高的, 但性能也是最差的, 因为服务器必须阻塞直到命令信息被写入并保存到磁盘之后, 才能继续处理请求。
综合起来,三种 AOF 模式的操作特性可以总结如下:
模式 | WRITE 是否阻塞? | SAVE 是否阻塞? | 停机时丢失的数据量 | |
---|---|---|---|---|
AOF_FSYNC_NO |
阻塞 | 阻塞 | 操作系统最后一次对 AOF 文件触发 SAVE 操作之后的数据。 | |
AOF_FSYNC_EVERYSEC |
阻塞 | 不阻塞 | 一般情况下不超过 2 秒钟的数据。 | |
AOF_FSYNC_ALWAYS |
阻塞 | 阻塞 | 最多只丢失一个命令的数据。 |
AOF 方式下的数据还原
Redis 读取 AOF 文件并还原数据库的详细步骤如下:
创建一个不带网络连接的伪客户端(fake client)。
读取 AOF 所保存的文本,并根据内容还原出命令、命令的参数以及命令的个数。
根据命令、命令的参数和命令的个数,使用伪客户端执行该命令。
执行 2 和 3 ,直到 AOF 文件中的所有命令执行完毕。
完成第 4 步之后, AOF 文件所保存的数据库就会被完整地还原出来。
注意, 因为 Redis 的命令只能在客户端的上下文中被执行, 而 AOF 还原时所使用的命令来自于 AOF 文件, 而不是网络, 所以程序使用了一个没有网络连接的伪客户端来执行命令。
当程序读入这个 AOF 文件时, 它首先执行 SELECT 0 命令 —— 这个 SELECT 命令是由 AOF 写入程序自动生成的, 它确保程序可以将数据还原到正确的数据库上。
注意:
为了避免对数据的完整性产生影响, 在服务器载入数据的过程中, 只有和数据库无关的订阅与发布功能可以正常使用, 其他命令一律返回错误。
AOF 的重写机制
为什么需要重写机制
AOF 文件通过同步 Redis 服务器所执行的命令, 从而实现了数据库状态的记录, 但是, 这种同步方式会造成一个问题: 随着运行时间的流逝, AOF 文件会变得越来越大。
对同一个键的状态的多次不同操作,而最终得到一个结果。比如对列表的添加删除元素。
被频繁操作的键。比如累加
重新机制是如何实现的
实际上, AOF 重写并不需要对原有的 AOF 文件进行任何写入和读取, 它针对的是数据库中键的当前值,也就是源数据从目前的内存中获取。
考虑这样一个情况, 如果服务器对键 list 执行了以下四条命令:
RPUSH list 1 2 3 4 // [1, 2, 3, 4]
RPOP list // [1, 2, 3]
LPOP list // [2, 3]
LPUSH list 1 // [1, 2, 3]
那么当前列表键 list 在数据库中的值就为 [1, 2, 3] 。
如果我们要保存这个列表的当前状态, 并且尽量减少所使用的命令数, 那么最简单的方式不是去 AOF 文件上分析前面执行的四条命令, 而是直接读取 list 键在数据库的当前值, 然后用一条 RPUSH 1 2 3 命令来代替前面的四条命令。
除了列表之外,集合、字符串、有序集、哈希表等键也可以用类似的方法来保存状态。
根据键的类型, 使用适当的写入命令来重现键的当前值, 这就是 AOF 重写的实现原理。
基本都步骤
for 遍历所有数据库:
if 如果数据库为空:
那么跳过这个数据库
else:
写入 SELECT 命令,用于切换数据库
for 选择一个库后,遍历这个库的所有键
if 如果键带有过期时间,并且已经过期,那么跳过这个键
if 根据数据的类型,进行相关操作。
AOF 的重写机制
AOF 保存的模式
Redis 目前支持三种 AOF 保存模式,它们分别是:
AOF_FSYNC_NO
:不保存。
AOF_FSYNC_EVERYSEC
:每一秒钟保存一次。(生产中一般选这种)
AOF_FSYNC_ALWAYS
:每执行一个命令保存一次
BGREWRITEAOF
只保存最终的name的值
AOF 重写的实现方式
方式 | 区别 |
---|---|
bgrewriteaof 命令 |
不需要重启服务,不便于统一管理 |
配置文件实现 | 需要重启服务,便于进行统一管理 |
bgrewriteaof
配置文件实现
触发条件,必须同时满足如下条件
aof_current_size
和aof_base_size
可以通过命令info persistence
查看到
重写流程图
对于上图有四个关键点
补充一下:
一: 在重写期间,由于主进程依然在响应
命令,为了保证最终备份的完整性
;因此它依然会
写入旧的AOF file
中,如果重写失败
,能够保证数据不丢失
。当然这个是可以通过配置
来决定在重写期间是否
进行主进程普通的AOF
操作。
二: 为了把重写期间响应
的写入信息也写入到新的文件
中,因此也会为子进程保留一个buf
,防止新写的file丢失数据
。
三: 重写是直接把当前内存的数据
生成对应命令
,并不需要
读取老的AOF文件
进行分析、命令合并。
四: AOF文件直接采用的文本协议
,主要是兼容性好、追加方便、可读性高可认为修改修复。
注意:无论是RDB还是AOF都是先写入一个临时文件,然后通过 rename 完成文件的替换工作。
重写机制操作实验:
- 修改
/etc/redis/6379.conf
文件
// 要想使用 AOF 的全部功能,需要设置为 yes
appendonly yes
// AOF 文件名,路径才看之前的 dir
配置项
appendfilename "appendonly.aof"
// 平常普通的 AOF 的策略
appendfsync everysec
// 当执行 AOF 重写时,是否继续执行平常普通的 AOF 操作。
// 这里设置文件 yes , 表示不执行
// 因为假如,同时执行,两种操作都会对磁盘 I/O 进行访问,造成
// I/O 访问量过大,产生性能衰减
no-appendfsync-on-rewrite yes
// AOF 文件容量的增长率
auto-aof-rewrite-percentage 100
// AOF 文件的最低容量,就是当前文件的大小大于此值时,就会进行重写。当然这只是其中一个条件。
auto-aof-rewrite-min-size 64mb
- 重启
supervisorctl restart redis-6379
-
redis-cli
查看配置文件修改后状态,并进行简单的数据添加操作
- 查看.aof文件
cat /var/lib/redis/appendonly-6379.aof
- 主动触发
BGREWRITEAOF
-
再次查看.aof文件,与上一次比较
RDB 和 AOF
区别:
如何抉择:
从服务器开启 RDB
始终开启 AOF
不要使用主机的全部内存