redis 作为我们经常使用的工具之一,熟悉它的特性还是很有必要的,这次写这篇文章也是在这方面吃了点亏, 我在参加某计算机考试时,有道题询问了这方面知识,原题我也记不大清楚了,我当时答的不是很好,感觉这种题丢分很不应该,所以写下文章,方便自我反省。
首先就是在开发中这个缓存应该是十分常用的,但是作为开发可能对于一些细节并没有很多的了解,毕竟业务压身,身不由己,有时候过来看看还是因为要面试,实在是惭愧,这篇文章我们先对 AOF RDB 做了一个回顾,然后从几个方面进行说明对比,分析他们的优缺点,选择合适的持久化方式。
从前两篇文章我们知道了 AOF 和 RDB 持久化的一些细节,忘了的可以再去看看哦!我们再来对比一下,什么环境选择什么持久化方式比较好?首先我们对两种持久化方式的过程进行回顾
AOF 持久化是类似 Mysql 的 binlog 日志,记录所有的修改操作,所有客户端发送的命令都以 Redis命令协议 格式进行追加保存, 为了保证文件大小的适当, Redis 还在后台对 AOF 文件进行子进程创建重写,使得 AOF 文件体积不会超出保存数据集状态所需的实际大写,并在服务器启动时,通过执行这些命令来还原数据集,要注意, Redis会优先使用 AOF 文件来还原数据, 因为 AOF 文本保存的数据集一般比 RDB 所保存的数据集更完整,并且 存储的文件一般也比 RDB 的文件大。
RDB 持久化是在指定的时间间隔内生成数据集的时间点快照,当满足配置文件里面的条件时,父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程, 然后子进程就会处理接下来所有的工作父进程无须执行任何磁盘 I/O 操作,在保存 Redis 里面的数据集时,它会利用 lzf算法 进行字符压缩,来保证文件大小适当,RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快,它不需要一条一条指令执行。
在 RDB 和 AOF 的写入上就有不同的特点,一个是追加写入,一个是保存整个数据集,从这两个操作的数据量上面就可以看出, RDB 在进行写入的时候不能太频繁了,要控制好频率,还有一个就是每次 fork 一个子进程,同时也阻塞命令的执行,虽然 fork 创建的子进程不需要拷贝父进程的物理内存空间,但是会复制父进程的空间内存页表。例如对于 10GB 的 Redis 进程,需要复制大约 20MB 的内存页表,因此 fork 操作耗时跟进程总内存量息息相关。对于高流量的 Redis 实例 OPS 可达5万以上,如果 fork 操作耗时在秒级别将拖慢 Redis 几万条命令执行,对线上应用延迟影响非常明显。正常情况下 fork 耗时应该是每 GB 消耗 20毫秒 左右。可以在info stats统计中查 latest_fork_usec 指标获取最近一次 fork 操作耗时,单位微秒。
RDB是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如每6小时执行 bgsave 备份,并把RDB文件拷贝到远程机器或者文件系统中(如hdfs),用于灾难恢复。Redis 加载RDB恢复数据远远快于AOF的方式。RDB方式数据没办法做到实时持久化/秒级持久化。因为 bgsave 每次运行都要执行 fork 操作创建子进程,属于重量级操作,频繁执行成本过高。RDB文件使用特定二进制格式保存, Redis 版本演进过程中有多个格式的RDB版本,存在老版本 Redis 服务无法兼容新版RDB格式的问题。RDB 不适合实时持久化的问题, Redis 提供了AOF持久化方式来解决。fsync 策略,可以较好地保证数据的完整性flushall 命令,只要 AOF 文件没有被重写,移除尾部 flushall 命令,重启就可以恢复之前的状态fsync 策略会降低性能(这属于一个权衡点)RBD 稍大如果 redis 里面存储的数据比较重要,你应该同时使用两种持久化功能。如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外,可还可以避免一些 AOF 的 BUG 。