我们之前的学习Redis都是基于内存来存储数据的,那么内存存储数据虽然其速率比关系性数据库快非常多,但是它的缺点就是断电即失
,如果没有持久化的话,那么这内存中的数据将丢失,并且没有办法去恢复这些数据!
那么Redis中的持久化有两种方式:RDB和AOF,这也是面试经常问到的持久化方式!必须掌握这两种持久化方式!
什么是RDB持久化?
RDB持久化就是通过硬盘来进行存储数据,当客户端在一定时间内操作次数满足了,那么这种机制就会将内存拍一张快照
,将这时刻的快照保存造硬盘中!
RDB工作原理
在进行RDB工作的时候,reids的主线程并不会进行任何io操作,而是然主线程fork一个子线程来完成该操作。
其RDB步骤:
Redis调用forks。同时拥有父进程和子进程
子进程将数据集写入一个临时RDB文件中
当子进程完成对新RDB文件的写入时,Redis用新的RDB文件替换为原来的RDB文件,并删除旧的RDB文件!
这种工作方式可以让Reids在从写复制(copy-on-write)机制中获利,因为子进程用来进行写操作,主线程依然可以处理客户端的请求!
save 命令
使用save命令,会立刻对当前内存中的数据进行持久化,但是会阻塞,期间不能进行其他的操作了
因为save命令是同步命令,会占用Redis的主进程。如果Redis数据非常多的时候,save命令执行速度就会非常慢,阻塞所有客户端的请求!
bgsave 命令
bgsave与save不同,bgsave是异步进行的,也就是说,持久化的过程不会占用主线程,而主线程依旧可以处理客户端的请求!
配置RDB
其实我们Redis中默认就是给我们开启RDB模式的,我们可以通过vim redis.conf来查看redis.conf文件
那么我们需要把这几个save放开,因为这里是注释,我们需要设置才会生效!
那么这些配置都是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文件,那么将持久化成功!
可以看到,我们进行了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持久化的条件
save的配置可以触发RDB的持久化
当我们退出Redis服务器的时候,会触发RDB
执行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关闭时,会进行一次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,但是你可以调节重写日志文件的频率来提高数据集的耐久度.
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相关的配置!
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的数据。
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服务端的时候,它首先会执行一次里面的语句,把数据还原出来!
如果AOF文件损坏了怎么办?
我们在安装redis的时候看过里面的目录,里面有一个AOF的修复工具
比如我们自己修改一下这个aof文件,让它报错
这时我们重启一下Redis服务端
可以看到,进程中没有Redis服务端,启动都启动不了!
那么我们用修复工具修复这个aof文件
再次查看aof文件
可以看到,设置k3的指令直接被删除了!
AOF工作原理
AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:
Redis 执行 fork() ,现在同时拥有父进程和子进程。
子进程开始将新 AOF 文件的内容写入到临时文件。
对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。
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)。
一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。
如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug。