Redis 持久化的 RDB 和 AOF

转自:https://gitbook.cn/books/5d5e83c19c87717d56207dc0/index.html

前面将了 Redis 的主从复制以及怎么搭建,还介绍了哨兵模式以及哨兵模式的搭建。虽然操作跟上了,但是还是补一下 Redis 的持久化。Redis 之所以这么流行,很大一部分原因便是持久化,断电重启数据不消失,使得 Redis 在数据库领域中站稳了脚。前文将的主从复制其实就是依赖持久化的,如果没有持久化,这些数据都不会从主服务器备份到从服务器。下文我们就讲讲 Redis 的持久化。

说起 Redis 持久化,大家或多或少都知道一些,简单点一句话也能概括。Redis 通过 RDB 和 AOF 方式将数据存入磁盘,实现持久化。RDB 是定期生成快照存入磁盘中,AOF 是将写操作存入磁盘中。二者各有优劣,RDB 是存放数据库中数据,适合做数据备份,但是数据可能不全,最近几分钟的数据可能没有。AOF 是每秒中执行一次,如果有写操作的命令就存储起来,最多只会丢失 1 秒钟的数据,适合做数据恢复。但是这个就不适合做数据备份了,并且由于每秒都会执行多多少少会抢占 Redis 的内存,会影响性能。但是在实际应用中是二者是配合使用的。

下面就来具体的讲讲 RDB 和 AOF 吧

RDB

RDB 的全称是 Redis database. 顾名思义,RDB 就是将 Redis 数据库,用来存储数据的,所以通过 RDB 方式持久化就是将存在 Redis 内存中的数据写入到 RDB 文件中保存到磁盘上从而实现持久化的。

RDB 文件是一个压缩的二进制文件,通过这个文件可以还原 Redis 数据库的数据,从而达到数据恢复的目的,借用一下《Redis 设计与实现》讲的这张图,途中数据库状态可以理解为 Redis 内存中存储的数据。

Redis 持久化的 RDB 和 AOF

既然 RDB 持久化的方式是生成 RDB 文件,那么这个 RDB 文件是怎么生成的呢?

RDB 文件生成的方式有两种,一种是通过命令手动生成快照,还有一个是通过配置自动生成快照。下面我们来分别看看。

通过 save 和 bgsava 命令生成 RDB 文件

这两个命令都是可以直接运行的。

save 命令,会阻塞服务器进程,只有当 RDB 文件生成成功才会接着响应服务端的其他命令。

Redis 持久化的 RDB 和 AOF

而 bgsave ,既然有这个命令,肯定是和 save 有所不同的,bgsave 不会阻塞服务器进程,会创建一个子进程来创建 RDB 文件。

Redis 持久化的 RDB 和 AOF

但是注意的是使用 bgsave 命令的时候,虽然是通过子进程生成 RDB 文件,不会阻塞服务进程,其他的命令可以执行,但是有几个命令是不能执行的。

save 
bgsave
bgrewriteaof

在 bgsave 期间 服务器拒绝这三个命令,主要是方式线程间竞争产生问题。

通过配置文件自动生成 RDB

初了手动执行这两个命令外,还可以在配置文件中配合参数,达到条件的时候就会自动的生成 RDB。打开我们的配置文件 Redis.conf,找到如下图,这个是默认的配置。

Redis 持久化的 RDB 和 AOF

save 900 1 
表示在 900 秒内,如果发生了一次写操作,就触发 bgsave 命令生成 RDB

同理 
save 300 10 在 300 秒内,发生了 10 次写操作,就触发 bgsave

save 60 10000  在 60 秒内发生了 10000 次写操作,就触发 bgsave 

上面的这些可以进行配置,可以看到默认的设置,如果短时间内发生大量的写操作就会自动的触发 bgsave,生成 RDB 文件, 防止数据丢失。

好了,上面虽然说达到这三个条件中的一个,Redis 就会自动的生成 RDB 文件,那系统是怎样控制,又是怎样识别是否满足条件呢?

原来啊,服务器维持了一个 dirty 计数器,以及一个 lastsave 属性。

dirty 计数器记录着从上次 save/bgave 到现在发生了多少次写操作,没进行一次写操作,计数器就加 1。

比如

set a  123
计数器 dirty 加 1 

set a 123 b 234 c 456
计数器 dirty 加 3

而 lastsave 是 unix 时间戳,记录上次 save 或 bgsave 的时间。

有了这两个属性,就可以判断什么时候执行啦,Redis 服务器会周期性的执行 serverCron 函数,默认的话是每 100 毫秒执行一次。

这个 serverCron 函数先通过当前时间减去 lastsave 获取时间间隔。

如果 dirty 大于 saveparm.chranges,并且时间间隔大于 saveparm.seconds 那么就会触发 bgsave 生成 RDB 文件。

其中 saveparm.seconds 和 saveparm.chranges 分别对应的是配置文件中设置的 save 9001 等。

既然生成了 RDB 文件,我们只知道 RDB 是一个压缩的二进制文件,那 RDB 文件到底结构是什么样的呢?

我看了一下《Redis 设计与实现》没有怎么看明白哈哈,感兴趣的可以去看看。

RDB 方式就讲到这里了,记住 RDB 方式,是定时的执行 bgsave 命令生成 RDB 文件保存在磁盘上实现持久化的。适合数据备份,用于数据恢复可能会丢失最近几分钟的数据。

AOF

全称是 append only file. AOF 持久化的方式是通过 Redis 服务器记录保存下所有的写命令到 AOF 文件存放在磁盘上,实现持久化的,看下图:

Redis 持久化的 RDB 和 AOF

怎样采用 AOF 的方式持久化呢?

打开我们的配置文件,在配置文件中找到 appendonly 改成 yes 就可以采用 AOF 的方式备份了。

Redis 持久化的 RDB 和 AOF

我们启动 Redis 服务,为了测试方便,我们新启的一个 Redis 服务,数据库中没有任何 key。

Redis 持久化的 RDB 和 AOF

我们看看 appendonly.aof 也是没有任何东西的。

Redis 持久化的 RDB 和 AOF

现在我们存入一个 key

Redis 持久化的 RDB 和 AOF

然后我们来看下 AOF 文件的内容:

Redis 持久化的 RDB 和 AOF

可以看到,初了一些 $3 等一些特殊符号外我们可以看到我们执行的命令。

select 0
set a bbb

但是我们一些读操作的就不会记录。由此可见,AOF 持久化就是将所有的写操作存入 AOF 文件中,当数据恢复的时候,执行 AOF 文件中的命令就可以获取数据了。

我们接着来看那,我向数据库中先加一个 keyb,然后删除 keya

Redis 持久化的 RDB 和 AOF

好了,现在我们再来看看 AOF 文件中是什么情况。

Redis 持久化的 RDB 和 AOF

可以看到命令有:

select 0
set a bbb
set b ddd
del a

所以 AOF 文件中包含了这四条命令,到这大家有没有发现一个问题,如果我重复的对某一个 key 值进行操作,那么 AOF 文件中就会记录所有的操作命令,但是实际上只有最后一次操作才是有效的,那这个 AOF 文件中是不是就有很多冗余的数据呢?

实际上是这样的,那怎么解决这个问题呢?这里就要提到一个命令啦

BGREWRITEAOF

和 RDB 中的 save 以及 bgsave 是类似的。不过 bgrewriteaof 命令的作用是重写 AOF 文件,为什么要重写呢,就是为了解决 AOF 文件中冗余的问题。

我们先来手动执行一下这个命令

Redis 持久化的 RDB 和 AOF

然后看看 AOF 文件中的内容

Redis 持久化的 RDB 和 AOF

可以看到命令变成了

select 0
set b ddd

重写之后,AOF 的文件里的命令就是有效的啦,但是我们总不能自己手动执行 bgrewriteaof 命令吧,那我们在哪里配置呢?

在 Redis.conf 配置文件中有这两个参数。

Redis 持久化的 RDB 和 AOF

 auto-aof-rewrite-percentage 100

当 AOF 增长超过指定比例时,重写 log file, 设置为 0 表示不自动重写 Aof 日志,重写是为了使 aof 体积保持最小,而确保保存最完整的数据。

auto-aof-rewrite-min-size 64mb

触发 aof rewrite 的最小文件尺寸

也就是说在实际应用中,如果开启了 AOF 备份,可以设置这两个参数来重写 AOF 文件。

好了上面说了那么多,那 Redis 服务怎么通过 AOF 文件来恢复数据呢?

其实很简单,就是将 AOF 文件中的命令一条一条的读取出来执行。看下图

Redis 持久化的 RDB 和 AOF

最后再说一点嘿嘿。

我们在配置文件中同时启用了 RDB 和 AOF ,那么服务启动的时候,会在用那个文件来回复数据呢?

看下面这张图

Redis 持久化的 RDB 和 AOF

可以看到如果启动 AOF,就会采用 AOF 文件来回复数据,这是为什么呢,因为 AOF 文件更新的频率更高,模式一秒中一次,所以用 AOF 恢复的数据更加准确。

好了,只有这么多了哈哈,推荐大家看看《Redis 设计与实现》也不建议大家从头往后看,调感兴趣的看吧,毕竟里面还是有很多原理对我们而言也不是一定非得弄懂的,大概了解一下就行,我比较懒哈哈。

上一篇:Winform混合式开发框架访问Web API接口的处理


下一篇:RDS for MySQL 大表操作