Redis 持久化机制?RDB,AOF?这下弄明白了

您所在的位置:网站首页 save是什么 Redis 持久化机制?RDB,AOF?这下弄明白了

Redis 持久化机制?RDB,AOF?这下弄明白了

#Redis 持久化机制?RDB,AOF?这下弄明白了| 来源: 网络整理| 查看: 265

简单介绍线上 Redis 被攻击了?发生甚么事了?

这两天自己做项目,出现一个奇怪的问题。

前一天特地存在 Redis 里的数据,后一天来看就没有了,明明也没有设置过期时间。

更好玩的是 Redis 里数据有着几个「backup」,就像下图所示:

到底是备份了什么,给我数据都整没了。。。

把「backup」里的数据编码再一看:

好家伙,我一下来劲了,什么 「cleanfda」什么「init.sh」的, 这是被攻击了啊!

这样的攻击,黑客一般会删除数据库的数据,然后给你留下「backup」指引,告诉你这些被删除的数据他做了备份,然后你应该如何花钱赎你的数据。 查明被攻击的原因是 Redis 密码过于简单,而且没有隐藏端口,于是就被攻破了。。。

为什么 Redis 数据需要持久化? 补救上面的问题

重新部署 Redis 不是难事,但是数据丢了就不好玩了,线下测试阶段则需要一点一点调用接口重新构造数据,线上阶段那还可能面临更多严肃的问题。 像我这里还在本地测试,就得一点一点重新构造数据了。

为什么 Redis 需要持久化数据?

首先 Redis 是一个基于内存的数据库,那么一旦 Redis 宕机,内存中的数据将全部丢失。 于是我们需要持久化机制,将内存中的数据持久化到硬盘中去。 同时考虑到上面服务被攻击,或者数据迁移的可能性,数据持久化都可以减少损失,使 Redis 服务更加灵活。

Redis 持久化机制 Redis 主要有几种持久化机制?

Redis 提供4种持久化方案:

RDBAOF虚拟内存(VM)DISKSTORE

而真正被官方文档认可支持的持久化方式只有 RDB 和 AOF。于是本篇我们主要介绍并且实践 RDB 和 AOF 持久化机制。

RDB 什么是 RDB?

RDB 是 Redis DataBase 的缩写,可以称作快照/内存快照。同时 RDB 是 Redis 默认启用的持久化方案。 RDB 持久化就是把当前进程数据生成快照保存到磁盘上的过程,由于是某一时刻的快照,那么快照中的值要早于或者等于内存中的值。

RDB 的优点(这方面的内容需要读完 RDB 篇章才能充分理解) RDB文件是某个时间节点的快照,默认使用 LZF 算法进行压缩,压缩后的文件体积远远小于内存大小,适用于备份、全量复制等场景;Redis 加载 RDB 文件恢复数据要远远快于 AOF 方式;

RDB 的缺点(这方面的内容需要读完 RDB 篇章才能充分理解)

RDB 方式实时性不够,无法做到秒级的持久化。如果系统发生故障将丢失最后一次创建快照以后的数据。RDB 方式保存快照开销较大,每次调用 bgsave 都需要 fork 子进程,fork 子进程属于重量级操作,频繁执行成本较高。RDB 文件是二进制的,没有可读性,AOF 文件在了解其结构的情况下可以手动修改或者补全。版本兼容 RDB 文件问题。

RDB 持久化的触发方式

手动触发 执行 save 命令 save 命令效果

阻塞当前 Redis 服务器,直到 RDB 过程完成为止。

阻塞时间

对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用

被动触发 执行 bgsave 命令 bgsave 命令效果

Redis 进程 fork 一个子进程,用于执行 RDB 持久化,完成后自动结束。

阻塞时间

阻塞只发生在 fork 阶段,一般时间很短

bgsave 流程

其中 bgsave 操作可以由我们进入 Redis 客户端并且手动执行,也可以由 Redis 自动触发。

如何自动触发

redis.conf 中配置 save m n,即在 m 秒内有 n 次修改时,自动触发 bgsave 生成 rdb 文件主从复制时,从节点要从主节点进行全量复制时也会触发 bgsave 操作,生成当时的快照发送到从节点执行 debug reload 命令重新加载 Redis 时也会触发 bgsave 操作默认情况下执行 shutdown 命令时,如果没有开启 aof 持久化,那么也会触发bgsave 操作接下来我们将实践触发 RDB 持久化机制主动 save 触发 RDB在 redis-cli 下执行 save 命令初始条件(这里的初始条件需要记住,接下来的实践都将基于这个初始化进行)⭐️

我们首先找一个空的 Redis 数据库,往里面写入 num1, num2

127.0.0.1:6379> keys * (empty array) 127.0.0.1:6379> set num1 1 OK 127.0.0.1:6379> set num2 2 OK 127.0.0.1:6379> keys * 1) "num1" 2) "num2" 127.0.0.1:6379>

同时我们关注 Redis 的数据存储目录

root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data# ls root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data# 可以看到当前是没有任何数据的

基于「初始条件」我们执行 save 命令

127.0.0.1:6379> save OK

这个时候我们检查数据目录,发现多出来了一个dump.rdb文件

说明上面由于执行 save 命令主动触发了 RDB,将当前数据写入到了 rdb文件

断开/重启 redis-cli 自动触发 RDB

默认情况下执行 shutdown 命令触发 bgsave

基于「初始条件」,我们关闭客户端(执行 shutdown 命令)

127.0.0.1:6379> shutdown not connected>

这个时候我们检查数据目录,发现多出来了一个dump.rdb文件

root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data# ls dump.rdb

说明上面由于执行 shutdown 命令自动触发了 bgsave,将当前数据写入到了 rdb文件

我们重启 Redis 服务,并且检查数据库中的 key

127.0.0.1:6379> keys * 1) "num1" 2) "num2" 127.0.0.1:6379>

发现数据都还在,说明数据被 Redis 通过 dump.rdb 恢复了。 我们直接重启 Redis 服务,相当于执行了 reload,自动触发 bgsave

基于「初始条件」,我们直接重启 redis 服务 然后可以发现存储 RDB 文件的目录下出现新的 dump.rdb

root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data# ls dump.rdb以上的断开/重启触发 RDB 的机制,正是 Redis 默认情况下对数据的持久化保护手段,当然默认的 RDB 持久化保护还不仅仅如此,接下来我们将学习到 Redis 中默认的快照周期一样可以自动的持久化保护数据。redis.conf 配置快照周期触发 RDB在redis.conf中配置save m n,确定在 m 秒内有 n 次修改,自动触发bgsave

我们首先在redis.conf中进行 RDB 的快照周期配置

什么是快照周期?

内存快照虽然可以通过手动执行 save 或 bgsave 命令来进行,但生产环境下多数情况都会设置其周期性执行条件。

于是我们设置 save m n 就是为内存快照设置一个执行的周期,也就是快照周期。

Redis 中默认的快照周期设置

我们打开redis.conf定位到SNAPSHOTTING会看到以下内容:

# 默认的设置为: save 900 1 save 300 10 save 60 10000

意思是说只要满足以下三个条件中的任意一个,就会自动触发 bgsave:

服务器在 900 秒之内,对数据库进行了至少 1 次修改服务器在 300秒 之内,对数据库进行了至少 10 次修改                                              服务器在 60秒 之内,对数据库进行了至少 10000 次修改其它 RDB 相关配置 ## 设置成下面则是关闭 RDB 快照功能 # save "" ​ # 文件名称 dbfilename dump.rdb ​ # 文件保存路径 dir /data/ ​ # 如果持久化出错,主进程是否停止写入 stop-writes-on-bgsave-error yes ​ # 是否压缩 rdbcompression yes ​ # 导入时是否检查 rdbchecksum yes

dbfilename: RDB 文件在磁盘上的名称。 dir: RDB 文件的存储路径。默认设置为 “./”,也就是 Redis 服务的主目录。 stop-writes-on-bgsave-error: 如果快照操作出现异常(例如操作系统用户权限不够、磁盘空间写满等等)时,Redis 就会禁止写操作。这个特性的主要目的是使运维人员在第一时间就发现 Redis 的运行错误,并进行解决。 rdbcompression: 该属性将在字符串类型的数据被快照到磁盘文件时,启用 LZF 压缩算法。Redis 官方的建议是请保持该选项设置为 yes。 rdbchecksum: 一个64位的 CRC 冗余校验编码会被放置在 RDB 文件的末尾,以便对整个 RDB 文件的完整性进行验证。这个功能大概会多损失10%左右的性能,但获得了更高的数据可靠性。所以如果您的 Redis 服务需要追求极致的性能,就可以将这个选项设置为 no。

基于「初始条件」,在我们上面学习基础上,我们修改自己的 redis.conf 文件:

# 文件名称 dbfilename dump.rdb # 文件保存路径 dir /data # 是否压缩 rdbcompression yes # 30s内修改2次就bgsave save 30 2

然后重启 redis 服务,并且直接删除掉由于重启生成的 dump.rdb。

然后我们在 redis-cli 下写入两个数据:

127.0.0.1:6379> set num3 3 OK 127.0.0.1:6379> set num4 4 OK

等待30s,发现存储 rdb 文件的目录下出现了新的 dump.rdb

root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data# ls dump.rdb

说明上面配置的快照周期奏效了。

在学习完成 RDB 篇章后,我们回顾一下篇章开头讲的 RDB 的缺点有一个实时性不够,而这个实时性不够的缺点 Redis 提供了 AOF 来解决。AOF什么是 AOF?

将写命令添加到 AOF 文件(Append Only File)的末尾。 与快照持久化相比,AOF 持久化的实时性更好,因此已成为主流的持久化方案。 默认情况下 Redis 没有开启 AOF(append only file)方式的持久化 AOF 是日志形式的持久化方案,因此什么时候写日志是我们需要注意的

什么是写后日志?和写前日志有什么区别?

Redis 就是写后日志,即执行命令,先写内存,再写日志。日志里面记录的是每一条命令。

而 MySQL 就是写前日志(WAL 机制),通过写前日志,和两阶段提交,保证数据和逻辑的一致性。

为什么使用写后日志?

首先 Redis 是一个追求高性能的数据库。

由于我们是先执行命令后再写日志,这样错误的命令就不会被记录在日志,因此 AOF 避免了对命令的语法检查,避免了额外的检查开销

同时写后日志不会阻塞当前的写操作

AOF 同步选项/写回策略AOF 日志记录写命令的步骤命令追加(append)文件写入(write)文件同步(sync)命令追加步骤做了什么?

当 AOF 持久化功能打开了,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器的 aof_buf 缓冲区。

所以命令追加过程还是在「写内存」,而后面的文件写入和文件同步过程则是「写磁盘写日志」了。

文件写入和文件同步步骤需要专门制定策略以实现 AOF。Redis 提供了 3 种同步选项/写回策略

选项同步频率优点缺点always每个写命令都同步可靠性高,数据基本不丢失每个写命令都要落盘,性能影响较大everysec每秒同步一次性能适中宕机时丢失1s内的数据no让操作系统来决定何时同步性能好宕机时丢失数据较多

至于选择什么样的写回策略?那就是要根据性能和可靠性进行取舍了!

配置并打开 AOFRedis 中 AOF 相关配置 # appendonly参数开启AOF持久化 appendonly yes ​ # AOF持久化的文件名,默认是appendonly.aof appendfilename "appendonly.aof" ​ # AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的 dir /data/ ​ # 同步策略 # appendfsync always appendfsync everysec # appendfsync no ​ # aof重写期间是否同步 no-appendfsync-on-rewrite no ​ # 重写触发配置 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb ​ # 加载aof出错如何处理 aof-load-truncated yes ​ # 文件重写策略 aof-rewrite-incremental-fsync yes

appendonly: 默认情况下 AOF 功能是关闭的(no),将该选项改为 yes 打开 Redis 的 AOF 功能。

appendfilename: AOF 文件的名字。

appendfsync: 设置「真正执行」操作命令向 AOF 文件中同步的策略。

什么是真正执行?

为了保证操作系统中 I/O 队列的操作效率,应用程序提交的I/O操作请求一般是被放置在 linux Page Cache 中的,然后再由 Linux 操作系统中的策略自行决定正在写到磁盘上的时机。而 Redis 中有一个 fsync() 函数,可以将 Page Cache 中待写的数据真正写入到物理设备上

no-appendfsync-on-rewrite: always 和 everysec 的设置会使真正的 I/O 操作高频度的出现,甚至会出现长时间的卡顿情况,这个问题出现在操作系统层面上,所有靠工作在操作系统之上的 Redis 是没法解决的。 为了尽量缓解这个情况,Redis 提供了这个设置项,保证在完成 fsync 函数调用时,不会将这段时间内发生的命令操作放入操作系统的 Page Cache(这段时间 Redis 还在接受客户端的各种写操作命令)。 auto-aof-rewrite-percentage: 在生产环境下,技术人员不可能随时随地使用 BGREWRITEAOF 命令去重写 AOF 文件。所以更多时候我们需要依靠 Redis 中对 AOF 文件的自动重写策略。 该参数表示如果当前 AOF 文件的大小超过了上次重写后 AOF 文件的百分之多少后,就再次开始重写 AOF 文件。 例如该参数值的默认设置值为 100,意思就是如果 AOF 文件的大小超过上次 AOF 文件重写后的1倍,就启动重写操作。 auto-aof-rewrite-min-size: 表示启动 AOF 文件重写操作的 AOF 文件最小大小。如果 AOF 文件大小低于这个值,则不会触发重写操作。 在了解上面的配置选项后我们来自己实践一下

首先还是配置我们自己的 redis.conf 文件,我们打开 AOF:

# aof 文件存储位置 dir /data # appendonly参数开启AOF持久化 appendonly yes ​ # AOF持久化的文件名,默认是appendonly.aof appendfilename "appendonly.aof" ​ # 同步策略 appendfsync everysec

然后我们重启 Redis 服务,并且检查文件存储位置,发现多出来了新的appendonly.aof文件

root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data# ls appendonly.aof dump.rdb

至于上面为什么还有dump.rdb那是因为此时 RDB 还未关闭,RDB 和 AOF 同时打开了。于是我们重新修改一下配置:

# aof 文件存储位置 dir /data ​ # 关闭 rdb save "" ​ # appendonly参数开启AOF持久化 appendonly yes ​ # AOF持久化的文件名,默认是appendonly.aof appendfilename "appendonly.aof" ​ # 同步策略 appendfsync everysec

重启 Redis 并检查,发现现在只有appendonly.aof了:

root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data# ls appendonly.aof root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data# cat appendonly.aof root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data#

该aof文件当前为空,然后我们执行命令,往 Redis 中写入数据:

127.0.0.1:6379> set num1 1 OK 127.0.0.1:6379> set num2 2 OK

再次检查appendonly.aof文件:

root@VM-4-6-debian:/var/lib/docker/volumes/redis-data/_data# cat appendonly.aof *2 $6 SELECT $1 0 *3 $3 set $4 num1 $1 1 *3 $3 set $4 num2 $1 2

发现我们执行的写命令都按照格式写入到 aof 文件中了。

接着我们关闭 Redis 连接,来测试一下 AOF 持久化的数据恢复:

127.0.0.1:6379> shutdown not connected>

然后重启 Redis 服务,并且检查数据:

127.0.0.1:6379> ping PONG 127.0.0.1:6379> keys * 1) "num2" 2) "num1"

数据成功的通过 AOF 恢复了!

持久化中恢复数据持久化做完了,也产生了持久化文件了。那么我们如何从持久化中恢复数据?如果又有 RDB 文件又有 AOF 文件,应该如何加载?

想从这些文件中恢复数据实际上只需要重启 Redis 服务就行了。(这也是我们上面实践一直在做的恢复操作)

然后 Redis 会经过下面的流程来执行恢复:

所以说,重启 Redis 的时候会进行判断,如果开启了 AOF,则优先加载 aof 文件。加载成功则 Redis 重启成功,加载失败,则会打印日志表示启动失败,那么需要去修复 aof 文件后重新启动。 如果 aof 文件不存在,那么 Redis 去加载 rdb 文件,如果 rdb 文件不存在,则 Redis 直接重启成功。如果 rdb 文件存在,则去加载 rdb 文件,如加载失败则打印日志提示启动失败,如加载成功,那么 Redis 重启成功,且使用 rdb 文件恢复数据; 其中通过以上过程,我们要知道 Redis 优先加载 aof 文件的原因是因为 AOF 保存的数据更加完整。

小结

本篇文章我们从 Redis 数据持久化的需求出发,详细介绍了 RDB 和 AOF 持久化机制,并且从多角度实践了这两种持久化机制,分析了其中的原理。最后我们分析了 Redis 从持久化文件中加载数据的机制。通过本篇文章应该可以对于 Redis 持久化机制形成一个较为全面的了解。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3