1、Redis持久化
Redis 提供了不同级别的持久化方式:
- RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。(快照/副本)
- AOF(Append-only file)持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。(日志)
- 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
- 你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
- 最重要的事情是了解RDB和AOF持久化方式的不同,让我们以RDB持久化方式开始:
管道技术:
- 衔接,前一个命令的输出作为后一个命令的输入
- 管道会触发创建【子进程】,管道左边和右边各创建一个进程
#当前进程的id号
[root@node02 ~]# echo $$
1231
#管道左边的进程号
[root@node02 ~]# echo $BASHPID |more
1277
#每次都创建新的进程
[root@node02 ~]# echo $BASHPID |more
1279
linux中父子进程
父进程的数据,子进程可不可以看得到?
- 常规思想,进程是数据隔离的!
[root@node02 ~]# echo $num
1
#创建一个子进程
[root@node02 ~]# /bin/bash
[root@node02 ~]# pstree
systemd─┬─NetworkManager───2*[{NetworkManager}]
├─VGAuthService
├─auditd───{auditd}
├─crond
├─dbus-daemon───{dbus-daemon}
├─firewalld───{firewalld}
├─login───bash
├─master─┬─pickup
│ └─qmgr
├─polkitd───6*[{polkitd}]
├─redis-server───3*[{redis-server}]
├─rsyslogd───2*[{rsyslogd}]
├─sshd───sshd───bash───bash───pstree#有两个bash进程
├─systemd-journal
├─systemd-logind
├─systemd-udevd
├─tuned───4*[{tuned}]
└─vmtoolsd───{vmtoolsd}
#什么也没输出,在子进程中访问不到父进程中的变量
[root@node02 ~]# echo $num
#退出子进程
[root@node02 ~]# exit
exit
- 进阶思想,父进程其实可以让子进程看到数据!
# num使用 export
#Linux export命令会标记哪些值需要传递给一组子进程。
[root@node02 ~]# export num
[root@node02 ~]# echo $num
1
#开启新的子进程
[root@node02 ~]# /bin/bash
[root@node02 ~]# pstree
systemd─┬─NetworkManager───2*[{NetworkManager}]
├─VGAuthService
├─auditd───{auditd}
├─crond
├─dbus-daemon───{dbus-daemon}
├─firewalld───{firewalld}
├─login───bash
├─master─┬─pickup
│ └─qmgr
├─polkitd───6*[{polkitd}]
├─redis-server───3*[{redis-server}]
├─rsyslogd───2*[{rsyslogd}]
├─sshd───sshd───bash───bash───pstree#有两个bash进程
├─systemd-journal
├─systemd-logind
├─systemd-udevd
├─tuned───4*[{tuned}]
└─vmtoolsd───{vmtoolsd}
#在子进程中获得到父进程的变量
[root@node02 ~]# echo $num
1
- 子进程中修改数据父进程中能否看到修改的数据?? 不能!!
#测试子进程中修改数据父进程能否被影响
#创建一个脚本文件进行测试
[root@node02 ~]# vi test.sh
#脚本中的内容如下
[root@node02 ~]# cat test.sh
#!/bin/bash
echo pid:$$
echo $num
num=999
echo num:$num
sleep 20
echo $num
#改变脚本的权限让他时可执行文件
[root@node02 ~]# chmod +x test.sh
#执行脚本文件
#&表示运行脚本是后台运行的
[root@node02 ~]# ./test.sh &
#脚本运行结果
[1] 1319
#脚本运行结果 子进程号
[root@node02 ~]# pid:1319
#运行结果:获取到父进程的变量并修改父进程变量为999
1
num:999
#父进程号
[root@node02 ~]# echo $$
1231
#子进程修改后没有影响到父进程中的变量值
[root@node02 ~]# echo $num
1
#子进程中最后的结果
[root@node02 ~]# 999
- 父进程中修改数据子进程中能否看到修改的数据?? 不能!!
#执行脚本
[root@node02 ~]# ./test.sh &
[1] 1339
[root@node02 ~]# pid:1339
1
num:999
#父进程的id号
[root@node02 ~]# echo $$
1231
#父进程的变量值
[root@node02 ~]# echo $num
1
#父进程修改变量值
[root@node02 ~]# num=888
[root@node02 ~]# echo $num
888
#父进程修改变量值没有影响到子进程
[root@node02 ~]# 999
结论:linux中export的环境变量,子进程的修改不会破坏父进程,父进程的修改也不会破坏子进程。
2、RDB持久化技术
在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。你可以对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次数据集。你也可以通过调用 SAVE或者 BGSAVE , 手动让 Redis 进行数据集保存操作
工作方式
-当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:
- Redis 调用forks. 同时拥有父进程和子进程。
- 子进程将数据集写入到一个临时 RDB 文件中。
- 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。
redis采用RDB持久化时,redis的父进程会系统调用fork()系统方法创建出一个子进程,父进程继续接受用户请求,子进程完成持久化工作。父进程在接受请求时修改数据,也不会影响到子进程的数据。
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,但是你可以调节重写日志文件的频率来提高数据集的耐久度.
2、AOF持久化技术
以日志的形式记录Redis每一个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件不可以改写文件,redis启动之后会读取appendonly.aof文件来实现重新恢复数据,完成恢复数据的工作。默认不开启,需要将redis.conf中的appendonly no改为yes启动Redis。
redis持久化策略
- appendfsync always 每修改同步,每一次发生数据变更都会持久化到磁盘上,性能较差,但数据完整性较好。非常慢,也非常安全
- appendfsync everysec 每秒同步,每秒内记录操作,异步操作,如果一秒内宕机,有数据丢失。足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。
- appendfsync no 从不。将数据交给操作系统来处理。更快,也更不安全的选择。
日志重写
因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。
为了处理这种情况, Redis 支持一种有趣的特性: 可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。执行 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令。
工作原理
AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:
- Redis 执行 fork() ,现在同时拥有父进程和子进程。
- 子进程开始将新 AOF 文件的内容写入到临时文件。
- 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
- 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
- 搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。
AOF优点:
- 使用AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据.
- AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题.
- Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
- AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。
- AOF缺点:
- 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
- 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。
3、如何选择使用哪种持久化方式?
一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。
如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug 。
Note: 因为以上提到的种种原因, 未来我们可能会将 AOF 和 RDB 整合成单个持久化模型。 (这是一个长期计划。) 接下来的几个小节将介绍 RDB 和 AOF 的更多细节