一:Redis持久化有哪些方式?
二:RDB持久化触发方式有哪些?
三:RDB持久化优缺点?
四:简述bgsave过程?
五:简述AOF工作流程?
六:AOF缓冲区同步文件策略有哪些?
七:AOF重写触发条件?
八:简述AOF重写过程?
九:RDB和AOF持久化文件损坏如何处理?
一: Redis持久化有哪些方式?
1.RDB 持久化
将当前进程数据生成快照保存到硬盘。
2.AOF 持久化 (append only file)
以独立日志方式记录每次写命令,重启时再重新执行 AOF 文件中的命令达到恢复数据的目的。 AOF 的主要作用是解决了数据持久化的实时性,目前已经是 Redis 持久化的主流方式。
二: RDB 持久化触发方式有哪些?
触发 RDB 持久化过程分为手动触发和自动触发。
手动触发命令有 save 和 bgsave :
save 命令:
阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存较大的实例会造成长时间阻塞,线上环境不建议使用,运行 save 命令对于 Redis 日志如下 :
* DB saved on disk
bgsave 命令:
Redis 进程执行 fork 操作创建子进程, RDB 持久化过程由子进程负责,完成后自动结束。
阻塞只发生 fork 阶段,一般时间较短。运行 bgsave 命令对应 redis 日志如下 :
* Backgroup saving start by pid xxx
* DB saved on disk
* RDB:0 MB of memory used by copy-on-write
* Backgroup saving terminated with success
RDB 自动触发有如下几个场景:
- 使用 save 相关配置,如 save m n 。表示 m 秒内数据集存在 n 次修改时,自动触发 bgsave 。
- 从节点执行全量复制操作,主节点自动执行 bgsave 生成 RDB 文件并发送给从节点。
- 执行 debug reload 命令重新加载 redis 时。
- 默认情况下执行 shutdown 命令时,如果没有开启 AOF 持久化功能,则自动执行 bgsave 。
三: RDB 持久化优缺点?
优点 :
1.RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照,适合用于备份,全量复制等场景。
2.Redis 加载 RDB 恢复数据远远快于 AOF 的方式。
缺点:
1.RDB 方式数据没办法做到实时持久化 / 秒级持久化。
2.bgsave 每次运行都需要执行 fork 操作创建子进程,属于重量级操作,频繁执行成本过高。
3.RDB 文件使用特定二进制格式保存, Redis 版本演进过程中有多个格式 RDB 版本,存在老版本 Redis 服务无法兼容新版本 RDB 格式的问题。
四:简述 bgsave 过程?
- 执行 bgsave 命令, Redis 父进程判断当前是否存在正在执行的子进程,如果 RDB/AOF 子进程,如果存在,直接返回。
- 父进程执行 fork 操作创建子进程, fork 操作过程中父进程会阻塞,通过 info stats 命令查看 lastest_fork_usec 选项,可以获取最近一个 fork 操作耗时,单位为微秒。
fork 创建子进程不需要拷贝父进程物理内存空间,但是会复制父进程空间内存页表。例如 10GB 的 redis 进程,需要复制大约 20MB 的内存页表,因此 fork 操作耗时跟进程总内存量息息相关。
对于高流量的 redis 实例 OPS(operation per second 每秒操作次数 ) 可达 5 万以上,如果 fork 操作耗时在秒级别,将会拖慢 redis 几万条命令执行。正常情况下 fork 耗时应该是每 GB 耗时 20 毫秒左右。 - 父进程 fork 完成后, bgsave 命令返回” Backgroup saving started “信息并不再阻塞父进程,可以继续响应其他命令。
- 子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行 lastsave 命令可以获取最后一次生成 RDB 时间,对应 inof 统计的 rdb_last_save_time 选项。
- 进程发送信号给父进程表示完成,父进程更新统计信息,具体见 info Persistence 下的 rdb_* 相关选项。
五:简述 AOF 工作流程
- 所有写命令会追加到 aof_buf( 缓冲区 ) 中。
2.AOF 缓存区根据对应的策略向硬盘做同步操作。 - 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
- 当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。
六: AOF 缓冲区同步文件策略有哪些?
由参数 appendfsync 控制,主要有下面三种配置:
1.always
命令写入 aof_buf 后调用系统 fsync 操作同步到 AOF 文件, fsync 完成后返回。
2.everysec
命令写入 aof_buf 后调用系统 write 操作, write 完成后线程返回。 fsync 同步文件操作由专门线程每秒调用一次。这也是建议的同步策略,也是默认配置,做到兼顾性能和数据安全性。
3.no
命令写入 aof_buf 调用系统 write 操作,不对 AOF 文件做 fsync 同步,同步硬盘操作由操作系统负责,通常同步周期最长 30 秒。
七: AOF 重写触发条件?
手动触发:
直接调用 bgrewriteaof 命令。
自动触发:
根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定自动触发时机。
其中:
auto-aof-rewrite-min-size: 表示运作 AOF 重写时文件最小体积,默认 64MB 。
Auto-aof-rewrite-percentage: 表示运行 AOF 文件空间 (aof_current_size) 和上一次重写后 AOF 空间 (aof_base_size) 的比值。
自动触发时间 = aof_current_size > auto-aof-rewrite-min-size && (aof_current_size - aof_base_size) / aof_base_size >= auto-aof-rewrite-percentage 。
其中 aof_current_size 和 aof_base_size 可以在 info Persistence 统计信息中查看。
八:简述 AOF 重写过程
- 执行 AOF 重写请求。
如果当前进程正在执行 AOF 重写,请求不执行并返回如下响应 :
ERR Backgroud append only file rewriting already in progress
如果当前进程正在执行 bgsave 操作,重写命令延时到 bgsave 完成之后再执行,返回如下响应: Background append only file rewriting scheduled - 父进程执行 fork 创建子进程,开销等同于 bgsave 过程。
- 主进程 fork 操作完成后,继续响应其他命令。所有修改命令依然写入 AOF 缓冲区,并根据 appendfsync 策略同步到硬盘,保证原有 AOF 机制正确性。
由于 fork 操作运用写时复制技术,子进程只能共享 fork 操作时的内存数据。由于父进程依然响应命令, Redis 使用 AOF 重写缓冲区保存这部分新数据,防止新 AOF 文件生成期间丢失这部分数据。 - 子进程根据内存快照,按照命令合并规则写入到新 AOF 文件。每次批量写入硬盘数据量由配置 aof-rewrite-incremental-fsync 控制,默认 32MB ,防止单次刷盘数据过多造成硬盘阻塞。
- 新 AOF 文件写入完成后,子进程发送信号给父进程,父进程更新统计信息,具体见 info persistence 下的 aof_* 相关统计。
父进程把 AOF 重写缓冲区的数据写入到新的 AOF 文件。
使用新 AOF 文件替换老文件,完成 AOF 重写。
九: RDB 和 AOF 持久化文件损坏如何处理?
1.RDB 文件损坏
RDB 文件保存位置在 dir 配置指定的目录下,文件名通过 dbfilename 配置指定。
可以通过执行 config set dir {newDir} 和 confg set dbfilename {newFileName} 动态修改,当下次运行 RDB 文件会保存到新目录。
当遇到坏盘或磁盘写满等情况,可以通过 config set dir {newDir} 在线修改文件路径到可用磁盘路径,之后执行 bgsave 进行磁盘切换,同样适用于 AOF 持久化文件。
如果在 redis 启动时加载的 RDB 文件已经损坏,会拒绝启动,并打印如下日志:
Short read or OOM loading DB. Unrecoverable error,aborting now.
这时可以使用 redis 提供的 redis-check-dump 工具检测 RDB 文件并获取对应的错误报告。
2.AOF 文件损坏
对于错误格式的 AOF 文件,先进行备份,然后采用 redis-check-aof --fix 命令进行修复,修复后使用 diff -u 对比数据差异,找出丢失数据,有些可以人工修补全。
AOF 文件可能存在结尾不完整的情况,比如机器突然断电导致 AOF 尾部文件命令写入不全。 Redis 提供了 aof-load-truncated 配置来兼容这种情况,默认开启。加载 AOF 时,当遇到此问题时会忽略并继续启动,同时打印如下警告日志 :
# !!! Warning: short read while loading the AOF file !!!
# !!! Truncatin the AOF at offset xxxxxx!!!
# AOF loaded anyway because aof-load-truncated is enabled
十:简述 AOF 追加阻塞
当开启 AOF 持久化时,常用的同步硬盘的策略是 everysec ,用于平衡性能和数据安全性。对于这种方式, Redis 使用另一条线程每秒执行 fsync 同步硬盘。当系统硬盘资源繁忙时,会造成 redis 主线程阻塞。
阻塞流程分析:
- 主线程负责写入 AOF 缓冲区。
2.AOF 线程负责每秒执行一次同步磁盘操作,并记录最近一次同步时间。 - 主线程负责对比上次 AOF 同步时间 :
如果距离上次同步成功时间在 2 秒内,主线程直接返回。
如果距离上次同步成功时间超过 2 秒,主线程将会阻塞,直到同步完成。
当发生 AOF 追加阻塞时,在 info Persistence 统计中, aof_delayed_fsync 指标会累加,查看这个指标方便定位 AOF 阻塞问题。日志会提示如下内容 :
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.
通过 AOF 阻塞流程可以发现两个问题:
1.everysec 配置最多可能丢失 2 秒数据,不是 1 秒。
2. 如果系统 fsync 缓慢,将会导致 Redis 主线程阻塞,影响效率。
参考:
《 Redis 开发与运维》
欢迎关注我的公众号《IT小Chen》