Redis 有两种持久化方案,RDB (Redis DataBase)和 AOF (Append Only File)。
RDB
RDB 是 Redis 默认的持久化方案。在指定的时间间隔内(周期性),执行指定次数的写操作,则会将内存中的数据写入到磁盘中。即在指定目录下生成一个dump.rdb文件。Redis 重启会通过加载dump.rdb文件恢复数据。触发RDB持久化过程分为手动触发和自动触发。
相关的命令使用
save命令: 阻塞当前Redis服务器, 直到RDB过程完成为止, 对于内存比较大的实例会造成长时间阻塞, 线上环境不建议使用。
bgsave命令: Redis进程执行fork操作创建子进程, RDB持久化过程由子进程负责, 完成后自动结束。
压缩
优缺点
-
RDB是一个紧凑压缩的二进制文件, 代表Redis在 某个时间点上的数据快照。 非常适用于备份, 全量复制等场景。
-
Redis加载RDB恢复数据远远快于AOF的方式。
-
RDB方式数据没办法做到实时持久化/秒级持久化。 因为bgsave每次运行都要执行fork操作创建子进程, 属于重量级操作, 频繁执行成本过高。
-
RDB文件使用特定二进制格式保存, Redis版本演进过程中有多个格式的RDB版本, 存在老版本Redis服务无法兼容新版RDB格式的问题。
AOF
优缺点
AOF的具体流程:
-
所有的写入命令会追加到aof_buf(缓冲区) 中。
-
AOF缓冲区根据对应的策略向硬盘做同步操作。
-
随着AOF文件越来越大, 需要定期对AOF文件进行重写, 达到压缩的目的。
-
当Redis服务器重启时, 可以加载AOF文件进行数据恢复。
AOF缓冲区同步文件策略
-
always---命令写入aof_buf后调用系统fsync操作同步到AOF文件,fsync完成后线程使用。效率较低。不建议配置
-
everysec---命令写入aof_buf后调用系统write操作,write完成后线程返回。fsync同步文件操作由专门线程每秒调用一次。默认配置-兼顾性能和安全性,理论上只有在系统突然宕机的情况下丢失1秒的数据。
-
no---命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步,同步硬盘操作由操作系统负责,通常同步周期最常30秒。数据安全性无法保证
AOF的write操作和fsync操作
-
write操作会触发延迟写(delayed write) 机制。 Linux在内核提供页缓冲区用来提高硬盘IO性能。 write操作在写入系统缓冲区后直接返回。 同步硬盘操作依赖于系统调度机制, 例如: 缓冲区页空间写满或达到特定时间周期。同步文件之前, 如果此时系统故障宕机, 缓冲区内数据将丢失。
-
fsync针对单个文件操作(比如AOF文件) , 做强制硬盘同步, fsync将阻塞直到写入硬盘完成后返回, 保证了数据持久化。
AOF重写机制
-
进程内已经超时的数据不再写入文件。
-
旧的AOF文件含有无效命令。
-
多条写命令可以合并为一个。
Redis重写AOF或RDB文件时出现的问题:
1.fork操作
当Redis做RDB或AOF重写时, 一个必不可少的操作就是执行fork操作创建子进程, 对于大多数操作系统来说fork是个重量级操作。 虽然fork创建的子进程不需要拷贝父进程的物理内存空间, 但是会复制父进程的空间内存页表。 例如对于10GB的Redis进程, 需要复制大约20MB的内存页表, 因此fork操作耗时跟进程总内存量息息相关, 如果使用虚拟化技术, 特别是Xen虚拟机, fork操作会更耗时。
fork耗时问题定位: 对于高流量的Redis实例OPS可达5万以上, 如果fork操作耗时在秒级别将拖慢Redis几万条命令执行, 对线上应用延迟影响非常明显。 正常情况下fork耗时应该是每GB消耗20毫秒左右。 可以在info stats统计中查latest_fork_usec指标获取最近一次fork操作耗时, 单位微秒。
如何改善fork操作的耗时:
1) 优先使用物理机或者高效支持fork操作的虚拟化技术, 避免使用Xen。
2) 控制Redis实例最大可用内存, fork耗时跟内存量成正比, 线上建议每个Redis实例内存控制在10GB以内。
3) 合理配置Linux内存分配策略, 避免物理内存不足导致fork失败, 具体细节见12.1节“Linux配置优化”。
4) 降低fork操作的频率, 如适度放宽AOF自动触发时机, 避免不必要的全量复制等。
2.AOF追加阻塞
同步硬盘的策略是everysec, 用于平衡性能和数据安全性。 对于这种方式, Redis使用另一条线程每秒执行fsync同步硬盘。 当系统硬盘资源繁忙时, 会造成Redis主线程阻塞。
阻塞流程分析:
1) 主线程负责写入AOF缓冲区。
2) AOF线程负责每秒执行一次同步磁盘操作, 并记录最近一次同步时间。
3) 主线程负责对比上次AOF同步时间:
-
如果距上次同步成功时间在2秒内, 主线程直接返回。
-
如果距上次同步成功时间超过2秒, 主线程将会阻塞, 直到同步操作完成。
通过对AOF阻塞流程可以发现两个问题:
1) everysec配置最多可能丢失2秒数据, 不是1秒。
2) 如果系统fsync缓慢, 将会导致Redis主线程阻塞影响效率。
AOF阻塞问题定位:
1) 发生AOF阻塞时, Redis输出如下日志, 用于记录AOF fsync阻塞导致拖慢Redis服务的行为:
Asynchronous AOF fsync is taking too long (disk is busy). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis
2) 每当发生AOF追加阻塞事件发生时, 在info Persistence统计中,aof_delayed_fsync指标会累加, 查看这个指标方便定位AOF阻塞问题。
3) AOF同步最多允许2秒的延迟, 当延迟发生时说明硬盘存在高负载问题(优化系统硬盘负载即可), 可以通过监控工具如iotop, 定位消耗硬盘IO资源的进程。