大家都知道, Redis 之所以性能好, 读写快, 是因为 Redis 是一个内存数据库, 它的操作都几乎基于内存. 但是内存型数据库有一个很大的弊端, 就是当数据库进程崩溃或系统重启的时候, 如果内存数据不保存的话, 里面的数据就会丢失不见了. 这样的数据库并不是一个可靠的数据库.
所以数据的持久化是内存型数据库的重中之重. 它不仅提供数据保存硬盘的功能, 还可以借此用硬盘容量扩展数据存储空间, 使得 Redis 的可以存储超过机器本身内存大小的数据.
Redis 对于数据持久化提供了两种持久化的方案, RDB 与 AOF. 它们的原理和使用场景都大不相同, 下面我们来详细地了解下.
RDB - 数据快照 (Snapshot)
RDB, 提供一个某个时间点的数据的 Snapshot, 保存在 RDB 文件中. 它可以通过 SAVE/BGSAVE 命令手动执行, 把数据 Snapshot 写到 RDB 文件, 也可以通过配置, 定时执行.
Redis 也可以通过加载 RDB 文件, 把数据从磁盘加载读取到 Redis 中.
RDB 文件创建
连上 Redis, 设值一些值, 然后执行 SAVE 命令.
然后可以查看下 Redis.conf 的持久化工作目录. 进入目录可以看到保存了一个 dump.rdb 文件. 该文件是一个二进制文件, 无法直接正常打开.
至于 SAVE/BGSAVE 的区别, 就是前置是阻塞执行, 此时服务不会接受请求, 后者是 Fork 一个子进程出来, 由该进程去执行保存 RDB 文件的操作, 不影响用户请求.
P.S. Redis 是单进程的, 所以 BGSAVE 只能 Fork 一个子进程, 而不是创建一个线程处理.
以上是手动执行的过程. 但在生产我们很少会手动登上服务去执行操作, 所以更多的时候是依赖 Redis 的配置, 定时保存 RDB 文件.
打开 Redis.conf 配置文件, 找到 SNAPSHOTTING 的配置, Save Point 的设置.
图中的配置意思是, 当至少有一个 key 变更时, 900 秒后会执行一次 SAVE. 其他配置同理, 有 10 次变更, 300 秒后保存一次.....
在 Redis 中, 这个自动保存 RDB 的功能是默认开启的.
RDB 文件加载
先 kill 掉 Redis 进程, 再重新启动 Redis Server, 会发现日志会有这样的一行,
并且 Redis 中, 依然有之前设置的三个值. 说明 Redis 在启动的时候, 会加载数据初始化.
不过, 这里加载的初始化数据不一定是 RDB 的. 如果 Redis 开启了 AOF, 会优先从 AOF 初始化数据, 否则才会加载 RDB 的数据.
RDB 优缺点
优点
RDB 是某一时间点的快照, 是一个紧凑的单文件, 更多用于数据备份. 可以按每小时或每日来备份, 方便从不同的版本恢复数据.
单文件容易传输到远程服务做故障恢复.
RDB 可以 Fork 子进程进行持久化, 使 Redis 可以更好地处理用户请求.
在大量数据的情况下, RDB 相比较于 AOF 会更快的加载.
缺点
如果 Redis 不及时保存 RDB 文件, 会造成数据的丢失. 例如系统突然断电, 但未来得及保存数据. 即使你设置更多的 Save point, 也无法保证 100% 的数据不丢失.
RDB 经常需要 fork 子进程去执行, 但如果再大量数据的情况下, 这个 fork 操作会非常耗 CPU 资源的. 对比 AOF 虽然也是 fork, 但是它的数据保存处理是可以控制的, 不需要全量保存.
AOF - 日志追加
Redis 的另外一种持久化方案就是 AOF,Append Only File.AOF 相当于一个操作的日志记录, 每次对于数据的变更都会记录追加到 AOF 日志. 当服务启动的时候就会读这些操作日志, 重新执行一次操作, 从而恢复原始数据.
AOF 启用
AOF 默认是关闭的. 打开 Redis.conf 配置文件, 找到 appendonly no 改成 appendonly yes .
AOF 和 RDB 是可以共存的, 只要保存的文件名不冲突.
fsync 同步规则
配置文件往下拉, 看到 fsync 的配置.
fsync() 是一个系统调用函数, 告诉操作系统把数据写到硬盘上, 而不是缓存更多数据才写到硬盘. 这样的调用可以及时保存数据到硬盘上.
Redis 提供了三种 fsync 的调用方式
appendfsync always, 每次操作记录都同步到硬盘上, 最低效, 最安全.
appendfsync everysec, 每秒执行一次把操作记录同步到硬盘上. 默认选项.
appendfsync no, 不执行 fysnc 调用, 让操作系统自动操作把缓存数据写到硬盘上, 不可靠, 但最快.
AOF 文件格式解析
开启 AOF 后, 会再工作目录看到 appendonly.aof 文件.
在客户端上执行一些命令后, 打开 AOF 文件, 可以观察到有对应的操作的记录日志.
文件解析说明:
*, 表示命令的参数个数, 例如 set a 1 是三个参数, 所以是 * 3
$, 表示参数的字节数, 例如 set 这个参数是三字节, 所以是 $3,key 值 a 是一个字节, 所以是 $1
无符号, 表示是参数的数据, 例如 set , a , 1 就是具体的数据
AOF 日志重写
AOF 虽然比 RDB 更可靠, 但缺点也是比较明显的, 就是每次写操作都要把操作日志写到文件上, 这样会导致文件非常冗余.
假若你要自增一个计数器 100 次, 如果不重写, AOF 文件就就会有这 100 次的自增记录, 如 INCR a . 如果执行了日志重写, 那么文件只会保留 set a 100 而不是 100 条 INCR a . 这样拥有相同的结果, 但可以大大减少 AOF 的文件大小, 并且可以让 AOF 载入的时候提升载入的效率.
看回 Redis.conf 配置, 有两项控制 rewrite 的选项.
auto-aof-rewrite-percentage 100, 当文件增长 100%(一倍) 时候, 自动重写.
auto-aof-rewrite-min-size 64mb, 日志重写最小文件大小, 如果小于该大小, 不会自动重写.
来实验一下重写的结果, 我们先设定一个 a 值, 然后自增多次, 查看 AOF 文件内容. 里面有很多 INCR 的语句记录.
然后我们手动执行下 BGREWRITEOF , 执行日志重写.
可以看到, 多个 incr 语句, 变成了一个 set a 6 语句, 减少了 5 个 incr a 语句的操作日志.
AOF 优缺点
优点
AOF 可以设置 完全不同步, 每秒同步, 每次操作同, 默认是每秒同步. 因为 AOF 是操作指令的追加, 所以可以频繁的大量的同步.
AOF 文件是一个值追加日志的文件, 即使服务宕机为写入完整的命令, 也可以通过 Redis-check-aof 工具修复这些问题.
如果 AOF 文件过大, Redis 会在后台自动地重写 AOF 文件. 重写后会使 AOF 文件压缩到最小所需的指令集.
AOF 文件是有序保存数据库的所有写入操作, 易读, 易分析. 即使如果不小心误操作数据库, 也很容易找出错误指令, 恢复到某个数据节点. 例如不小心 FLUSHALL, 可以非常容易恢复到执行命令之前.
缺点
相同数据量下, AOF 的文件通常体积会比 RDB 大. 因为 AOF 是存指令的, 而 RDB 是所有指令的结果快照. 但 AOF 在日志重写后会压缩一些空间.
在大量写入和载入的时候, AOF 的效率会比 RDB 低. 因为大量写入, AOF 会执行更多的保存命令, 载入的时候也需要大量的重执行命令来得到最后的结果. RDB 对此更有优势.
如何选择
以上已经基本了解过 RDB 和 AOF 的使用, 基本原理以及对应的优缺点. 那么在实际当中, 我们到底怎么去选择用哪种持久化方式呢?
一般来说, 不考虑硬盘大小, 最安全的做法是 RDB 与 AOF 同时使用, 即使 AOF 损坏无法修复, 还可以用 RDB 来恢复数据.
如果 Redis 的数据在你的服务中并不是必要的数据, 例如只是当简单的缓存, 没有缓存也不会造成缓存雪崩. 说明数据的安全可靠性并不是首要考虑范围内, 那么单独只使用 RDB 就可以了.
不推荐单独使用 AOF, 因为 AOF 对于数据的恢复载入来说, 比 RDB 慢. 并且 Redis 官方也说明了, AOF 有一个罕见的 bug. 出了问题无法很好的解决. 所以使用 AOF 的时候, 最好还是有 RDB 作为数据备份.
根据官方的意愿描述, 在未来可能会有一种 RDB 与 AOF 相结合的持久化模型. 到时 Redis 持久化就不再如此麻烦费劲了, 我们拭目以待吧.
来源: http://www.tuicool.com/articles/n2QZv2M