深入解析redis 三种持久化方式。

RDB

简介

RDB持久化方式是通过快照(snapshotting)完成的,当符合一定条件时,redis会自动将内存中所有数据以二进制方式生成一份副本并存储在硬盘上。当redis重启时,并且AOF持久化未开启时,redis会读取RDB持久化生成的二进制文件(默认名称dump.rdb,可通过设置dbfilename修改)进行数据恢复,对于持久化信息可以用过命令“info Persistence”查看。

save

该命令会由worker thread 执行,因此会阻塞 redis 的 worker 期间不会响应任何其他客户端发来的请求,直到RDB快照文件执行完毕,所以慎用。

测试

info persistence 
# rdb_last_save_time:1570126868
save
info persistence
# rdb_last_save_time:1570126928

bgsave

bgsave“后台保存”。与save 最大的差异为它并是由 worker thread 执行的,而是由redis fork 出子进程,交由子进程来完成持久化操作。

redis是在fork子进程这个时间段内 redis是阻塞的(此段时间不会响应客户端请求),当子进程创建完成以后redis响应客户端请求。

redis 不会再控制台显示完成信息,但是会写入日志。

流程

客户端执行bgsave命令,redis主进程收到指令并判断此时是否在执行bgrewriteaof(AOF文件重新过程,后续会讲解),如果此时正好在执行则bgsave直接返回,不fork子进程,如果没有执行bgrewriteaof重写AOF文件,则进入下一个阶段;

主进程调用fork方法创建子进程,在创建子进程过程中redis主进程阻塞,所以不能响应客户端请求;

子进程创建完成以后,bgsave命令返回Background saving started,此时标志着redis可以响应客户端请求了;

子经常根据主进程的内存副本创建临时快照文件,当快照文件完成以后对原快照文件进行替换;

子进程发送信号给redis主进程完成快照操作,主进程更新统计信息(info Persistence可查看),子进程退出;

测试

bgsave
Background saving started  # 子进程创建成功,它会去 完成持久化操作

查看日志

config get logfile
 11) "logfile"
 12) "/var/log/redis/redis-server.log"
cat "/var/log/redis/redis-server.log"
2497:M 04 Oct 2019 10:26:46.764 * Background saving started by pid 28960   # 开始后台 持久化
2497:M 04 Oct 2020 10:26:46.772 * Background saving terminated with success   # 后台持久化完成 

RDB相关配置

查看配置的方法:

1 查看配置文件

2 在redis 中查看当前 redis 的配置

CONFIG get *    # 获取所有的配置
CONFIG get dir   # 获取 快照文件 保存的 位置
CONFIG get dbfilename   # 获取 快照文件 的文件名

快照文件位置

配置文件中 dir 指定

快照文件名

配置文件中 dbfilename

是否压缩

配置文件中 rdbcompression default:yes

设置存储至本地数据库时是否压缩数据,默认为yes,采用LZF压缩

yes 会耗费一定的CPU资源,默认是 yes 。

no 会使存储的文件变大(巨大)

是否校验

配置文件中 yesrdbchecksumy default: yes

yes 会消耗一部分CPU资源,但是数据相对安全不容易损坏

no 可以节约读写性过程约10%时间消耗,但是存储一定的数据损坏风险

后台持久化报错

配置文件中 stop-writes-on-bgsave-error default: yes

后台存储过程中如果出现错误线程,是否停止保存操作,默认是停止的

no 则忽略错误继续。

快照检查

配置文件中 rdbchecksum default: yes
在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动。

RDB触发

自动触发

配置文件中 save default: yes

save second changes
# 查看默认的配置
config get save
"900 1 300 10 60 10000"
# 900秒内 1次键更新了就触发持久化 或 300秒内 10次更新 持久化 60 秒内 10000次更新 触发持久化
# 该持久化是 bgsave

手动触发

手动执行 savebgsave

其他触发

以下几种种情况下会触发执行快照操作,并且默认的使用bgsave

主从复制时,从库全量复制同步主库数据,此时主库会执行bgsave命令进行快照;

客户端执行数据库清空命令FLUSHALL时候,触发快照;

客户端执行shutdown关闭redis时,触发快照,也可以 使用 nosave 参数显式声明不保存快照

shutdown nosave

故障恢复

当redis意外崩溃或者关闭再次启动时,此时AOF持久化未开启时(默认未开启),将使用RDB快照文件恢复数据。

# 查看日志
cat /var/log/redis/redis-server.log
30448:M 04 Oct 2019 10:09:37.145 # Server initialized
30448:M 04 Oct 2019 10:09:37.145 * DB loaded from disk: 0.000 seconds   # 从快照恢复
30448:M 04 Oct 2019 10:09:37.146 * Ready to accept connections

缺点

RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具体较大的可能性丢失数据

bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能

Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现个版本服务之间数据格式无法兼容现象

存储数据量较大,效率较低——基于快照思想,每次读写都是全部数据,当数据量巨大时,效率非常低
大数据量下的IO性能较低

AOF

简介

日志形式的AOF,将命令追加到文件。AOF可以将Redis执行的每一条写命令追加到磁盘文件(appendonly.aof)中,在redis启动时候优先选择从AOF文件恢复数据。因为要频繁的将每一个操作记录到文件中,所以开启AOF持久化会对性能有一定的影响,但是大部分情况下这个影响是可以接受的。

与RDB持久化相比,AOF持久化数据丢失更少,其消耗内存更少(RDB方式执行bgsve会有内存拷贝)。

AOF持久化过程

redisAOF持久化过程可分为以下阶段:

追加写入

redis将每一条写命令以redis通讯协议添加至缓冲区aof_buf,这样的好处在于在大量写请求情况下,采用缓冲区暂存一部分命令随后根据策略一次性写入磁盘,这样可以减少磁盘的I/O次数,提高性能。

同步三种策略

当写命令写入aof_buf缓冲区后,redis会将缓冲区的命令写入到文件,redis提供了三种同步策略,由配置参数appendfsync决定,下面是每个策略所对应的含义:

no

不使用fsync方法同步,而是交给操作系统write函数去执行同步操作,在linux操作系统中大约每30秒执行一次 sync(man 2 sync 查看)。这种情况下,缓冲区数据同步不可控,并且在大量的写操作下,aof_buf缓冲区会堆积会越来越严重,一旦redis出现故障,数据丢失严重,整体不可控。

always

表示每次有写操作都调用fsync方法强制内核将数据写入到aof文件。这种情况下由于每次写命令都写到了文件中, 虽然数据比较安全,但是因为每次写操作都会同步到AOF文件中,所以在性能上会有影响,同时由于频繁的IO操作,硬盘的使用寿命会降低。

everysec

数据将使用调用操作系统write写入文件,并使用fsync每秒一次从内核刷新到磁盘。 这是折中的方案,兼顾性能和数据安全,所以redis默认推荐使用该配置。

文件重写

当开启AOF时,随着时间推移,AOF文件会越来越大,redis提出一种重写的策略来缓解数据存储和恢复压力。

重写策略

重复或无效的命令不写入文件

过期的数据不再写入文件

多条命令合并写入(当多个命令能合并一条命令时候会对其优化合并作为一个命令写入,例如“RPUSH list1 a RPUSH list1 b” 合并为“RPUSH list1 a b” )

触发条件

AOF文件触发条件可分为手动触发和自动触发:

手动触发:客户端执行bgrewriteaof命令。

自动触发:自动触发通过以下两个配置协作生效:

auto-aof-rewrite-min-size

AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写,4.0默认配置64mb。

auto-aof-rewrite-percentage

当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比,如100代表当前AOF文件是上次重写的两倍时候才重写。 

redis在AOF功能开启的情况下,会维持以下三个变量

aof_current_size :记录当前AOF文件大小

aof_rewrite_base_size:记录最后一次AOF重写之后,AOF文件大小

aof_rewrite_perc:增长百分比变量

每次当serverCron(服务器周期性操作函数)函数执行时,它会检查以下条件是否全部满足,如果全部满足的话,就触发自动的AOF重写操作:

没有BGSAVE命令(RDB持久化)/AOF持久化在执行;

没有BGREWRITEAOF在进行;

当前AOF文件大小要大于server.aof_rewrite_min_size的值;

当前AOF文件大小和最后一次重写后的大小之间的比率等于或者大于指定的增长百分比(auto-aof-rewrite-percentage参数)

重写过程

  AOF文件重写过程与RDB快照bgsave工作过程有点相似,都是通过fork子进程,由子进程完成相应的操作,同样的在fork子进程简短的时间内,redis是阻塞的,以下图文说明其重写过程:

开始bgrewriteaof,判断当前有没有bgsave命令(RDB持久化)/bgrewriteaof在执行,倘若有,则这些命令执行完成以后在执行。

主进程fork出子进程,在这一个短暂的时间内,redis是阻塞的。

当完成重写后,将重写后的aof 文件合并到原有aof缓存文件中。并删除临时创建的重写后的aof文件

AOF实现本质

AOF实现本质是基于redis通讯协议,将命令以纯文本的方式写入到文件中。

redis协议:

首先Redis是以行来划分,每行以\r\n行结束。每一行都有一个消息头,消息头共分为5种分别如下:

(+) 表示一个正确的状态信息,具体信息是当前行+后面的字符。

(-) 表示一个错误信息,具体信息是当前行-后面的字符。

() 表示消息体总共有多少行,不包括当前行,后面是具体的行数。

($) 表示下一行数据长度,不包括换行符长度\r\n,$后面则是对应的长度的数据。

(

版权声明:本文为monkey-code原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/monkey-code/p/13087736.html