Redis持久化

我们之前的学习Redis都是基于内存来存储数据的,那么内存存储数据虽然其速率比关系性数据库快非常多,但是它的缺点就是断电即失,如果没有持久化的话,那么这内存中的数据将丢失,并且没有办法去恢复这些数据!

那么Redis中的持久化有两种方式:RDB和AOF,这也是面试经常问到的持久化方式!必须掌握这两种持久化方式!

10.1、RDB持久化

什么是RDB持久化?

RDB持久化就是通过硬盘来进行存储数据,当客户端在一定时间内操作次数满足了,那么这种机制就会将内存拍一张快照

,将这时刻的快照保存造硬盘中!

RDB工作原理

在进行RDB工作的时候,reids的主线程并不会进行任何io操作,而是然主线程fork一个子线程来完成该操作。

其RDB步骤:

  1. Redis调用forks。同时拥有父进程和子进程

  2. 子进程将数据集写入一个临时RDB文件中

  3. 当子进程完成对新RDB文件的写入时,Redis用新的RDB文件替换为原来的RDB文件,并删除旧的RDB文件!

这种工作方式可以让Reids在从写复制(copy-on-write)机制中获利,因为子进程用来进行写操作,主线程依然可以处理客户端的请求!

Redis持久化

 

  • save 命令

使用save命令,会立刻对当前内存中的数据进行持久化,但是会阻塞,期间不能进行其他的操作了

因为save命令是同步命令,会占用Redis的主进程。如果Redis数据非常多的时候,save命令执行速度就会非常慢,阻塞所有客户端的请求!

  • bgsave 命令

bgsavesave不同,bgsave是异步进行的,也就是说,持久化的过程不会占用主线程,而主线程依旧可以处理客户端的请求!

配置RDB

其实我们Redis中默认就是给我们开启RDB模式的,我们可以通过vim redis.conf来查看redis.conf文件

Redis持久化

那么我们需要把这几个save放开,因为这里是注释,我们需要设置才会生效!

Redis持久化 

Redis持久化 

 

那么这些配置都是Redis默认帮我们配置好的,而且是默认开启的,那么我们就可以来测试一下这个RDB持久话

首先开启和连接到Redis服务端(这一步省略)

其次我们在5分钟内存储5个key

127.0.0.1:6379> set k1 v1			# 连续往redis中设置key
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> set k3 v3
OK
127.0.0.1:6379> set k4 v4
OK
127.0.0.1:6379> set k5 v5
OK	

 此时我们再ls一下,如果再默认路径下有这个dump.rdb文件,那么将持久化成功!

Redis持久化

可以看到,我们进行了5次写操作之后,就自动持久化成一个dump.rdb文件了

现在我们关闭服务器,然后再连一次服务器

127.0.0.1:6379> SHUTDOWN
not connected> exit
[root@localhost bin]# redis-server mconfig/redis.conf 
[root@localhost bin]# redis-cli -p 6379
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k4"
4) "k1"
5) "k5"

 

可以看到,我们Redis服务器启动的时候,会自动读取dump.rdb文件,并将文件里面的数据还原出来!所以我们在重启服务器之后,数据还是存在的!

触发rdb持久化的条件

  1. save的配置可以触发RDB的持久化

  2. 当我们退出Redis服务器的时候,会触发RDB

  3. 执行flushall命令,也会触发我们的rdb原则

证明第二条:

首先我们需要删除这个dump.rdb文件

[root@localhost bin]# rm -rf dump.rdb 
[root@localhost bin]# ls
mconfig  redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server

然后重新连接到Redis服务端,连接完后直接shutdown命令退出

127.0.0.1:6379> SHUTDOWN
not connected> exit

此时再一次ls查看文件

Redis持久化

那么证明Redis关闭时,会进行一次RDB持久化!

RDB的优点

引用官方文档的描述:

  • RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集.

  • RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复.

  • RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能.

  • 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些.

RDB的缺点

  • 如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据.

  • RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.

10.2、AOF持久化

AOF(Append-only file),只追加操作的文件,我们从上面RDB的缺点可以看出,它的持久化并不能保存短时间的数据,就比如说,你设置了5分钟操作100次就进行持久化,那么在99次操作完成后突然断电,服务器宕机,那么这99次操作或者这5分钟的数据全都丢失了,并且我们并不能恢复这5分钟内的数据!

对于这种情况,AOF可以做到每秒进行一次持久化, 它会将我们所有的命令都记录下来,history,恢复的时候就把这个文件全部再执行一遍!那么即使服务器宕机,断电了,我们只是丢失了那一秒的数据!

日志重写

因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。

为了处理这种情况, Redis 支持一种有趣的特性: 可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。执行 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令。Redis 2.2 需要自己手动执行 BGREWRITEAOF 命令; Redis 2.4 则可以自动触发 AOF 重写。

基本配置

我们还是编辑这个redis.conf文件,查看AOF相关的配置!

Redis持久化

Redis持久化 

no-appendfsync-on-rewrite no

当我们选择appendfsync为everysec的时候,Redis会每一秒都进行一次数据同步,并且把数据同步到磁盘中,这个运行起来的效率有点慢,因为要等待Redis把数据同步到磁盘中,这过程时阻塞的。当然我们还有两种选择方案,一种是always,表示总是写入AOF文件,并完成同步,这就意味着只要写一行,那么Redis就同步一行,这样的效率是非常低的,但是这种方式数据的安全性是最高的!还有一种是选择no,意味着写入操作和同步磁盘这两个操作是异步的,那么不会发生阻塞,效率是最快的,同时数据安全性也是最差的,所有Redis选择了一种折中的方法,那就是everysec!

那么如果no-appendfsync-on-rewrite no设置为no是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。

设置为yes就相当于appendfsync设置为no, 这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。丢失多少数据呢?在linux的操作系统的默认设置下,最多会丢失30s的数据。

Redis持久化

 

auto-aof-rewrite-percentage 100 : 当写入aof文件的大小是上一次写入的百分之100的时候(也就是两倍),会触发(rewrite)重写功能。 auto-aof-rewrite-min-size 64mb: 当aof文件的大小超过64mb的时候,就会触发重写功能!

重写(rewrite):

例如100条自增命令,重写时只需要一次set命令即可,省略了99条命令,减少了代码的冗余!

那么通过我们上面分析Redis一些配置,我们知道只要修改appendonly为yes,那么AOF持久化功能就可以开启,其他的都用默认的配置即可!

连接上Redis服务端后我们往里面设置一些值,测试这个AOF功能

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> set k3 v3
OK

 用ls命令查看一下文件

Redis持久化

可以看到确实有这个文件,我们可以查看一下里面的东西!

Redis持久化 

我们的命令确实被追加进去了,那么我们重启Redis服务端的时候,它首先会执行一次里面的语句,把数据还原出来!

如果AOF文件损坏了怎么办?

我们在安装redis的时候看过里面的目录,里面有一个AOF的修复工具

Redis持久化 

比如我们自己修改一下这个aof文件,让它报错

Redis持久化 

这时我们重启一下Redis服务端

Redis持久化

Redis持久化 

可以看到,进程中没有Redis服务端,启动都启动不了!

那么我们用修复工具修复这个aof文件

Redis持久化 

再次查看aof文件

Redis持久化 

可以看到,设置k3的指令直接被删除了!

AOF工作原理

AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:

  • Redis 执行 fork() ,现在同时拥有父进程和子进程。

  • 子进程开始将新 AOF 文件的内容写入到临时文件。

  • 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。

  • 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。

  • 搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。

Redis持久化 

 

AOF优点

  • 与RDB相比,当服务器宕机时候,最多只丢失一秒钟的数据,数据的完整性很高!

  • 当aof文件过大,会触发自动重写; 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。

  • AOF可以恢复出完整的数据集, 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

AOF缺点

  • 对于文件大小程度来说,AOF文件的体积往往比RDB文件的要大,而且AOF恢复数据的速度比RDB要慢

  • 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。

10.3、两种持久化的应用场景

一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。

如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。

有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug。

上一篇:Sentry 开发者贡献指南 - Feature Flag


下一篇:Redis高可用、持久化及性能管理