共计 2190 个字符,预计需要花费 6 分钟才能阅读完成。
更多内容,欢迎关注微信公众号:全菜工程师小辉~
Redis 提供了将数据定期自动持久化至硬盘的能力,包括 RDB 和 AOF 两种方案,两种方案分别有其长处和短板,可以配合起来同时运行,确保数据的稳定性。
RDB
保存数据快照至一个 RDB 文件中,用于持久化。RDB 操作和 Mysql Dump 相似。
执行方式
- save。同步操作,会阻塞 Redis。
- bgsave。调用 linux 的 fork(),然后使用新的线程执行复制。但是 fork 期间也会阻塞 Redis,但是阻塞时间通常很短。
- 自动保存。Redis 配置文件中设置了自动保存的触发机制,可以自定义修改,运行原理同 bgsave。
save 和 bgsave 的对比
注意:
- 如果机器上运行多个 Redis,需要配置 RDB 文件名称,否则多个 Redis 的 RDB 文件会相互覆盖。
除了上述三种执行方式,以下情况也会生成 RDB 文件:
- 主从的全量复制时,主机会生成 RDB 文件。
- Redis 中的 debug reload 提供 debug 级别的重启,不清空内存的一种重启,这种方式也会触发 RDB 文件的生成。
- 执行 shutdown 时,会触发 RDB 文件的生成。
RDB 的缺点
- 全量数据存储,耗时。
- 虽然 fork()采用 copy-on-write 策略,但仍消耗内存
- 写 RDB 文件消耗大量 IO 性能。
AOF
采用 AOF 持久方式时,Redis 会把每一个写请求都记录在一个日志文件里,AOF 操作和 Mysql Binlog 相似。通过 AOF 重写机制减少 AOF 文件的体积,从而减少恢复时间。
执行方式
- always。Redis 的每条写命令都写入到系统缓冲区,然后每条写命令都使用 fsync“写入”硬盘。
- everysec。过程与 always 相同,只是 fsync 的频率为 1 秒钟一次。这个是 Redis 默认配置,如果系统宕机,会丢失一秒左右的数据
- no。由操作系统决定什么时候从系统缓冲区刷新到硬盘。
AOF 重写
为了解决 AOF 文件体积膨胀的问题,Redis 提供了 AOF 重写功能:Redis 服务器可以创建一个新的 AOF 文件来替代现有的 AOF 文件,新旧两个文件所保存的数据库状态是相同的,但是新的 AOF 文件不会包含任何浪费空间的冗余命令,通常体积会较旧 AOF 文件小很多。
AOF 重写方式
- bgrewriteaof(流程与 bgsave 相似)
- AOF 重写配置(与 RDB 自动保存相似)
AOF 重写并不需要对原有 AOF 文件进行任何的读取,写入,分析等操作,这个功能是通过读取服务器当前的数据库状态来实现的。
RDB vs AOF
Redis 启动时的数据加载
Redis 启动数据加载流程:
- AOF 持久化开启且存在 AOF 文件时,优先加载 AOF 文件。
- AOF 关闭或者 AOF 文件不存在时,加载 RDB 文件。
- 加载 AOF/RDB 文件成功后,Redis 启动成功。
- AOF/RDB 文件存在错误时,Redis 启动失败并打印错误信息。
开发运维中常见的问题
fork 操作
fork()的实际开销就是复制父进程的页表以及给子进程创建一个进程描述符,所以速度一般比较快
内存量越大,耗时越长;物理机相对较快,虚拟机相对较慢。
优化方法
- 优先使用物理机或者高效支持 fork 操作的虚拟化技术
- 控制 Redis 实例最大可用内存 maxmemory
- 合理配置 Linux 内存分配策略:vm.overcommit_memory=1。默认值为 0,会使 Linux 在内存分配时,发现不够内存不足时,不会进行分配,进而造成 fork 阻塞
- 降低 fork 频率。例如放宽 AOF 重写自动触发时机或者减少不必要的主从全量复制
进程外开销
- CPU。RDB 和 AOF 文件生成,属于 CPU 密集型。不要将 Redis 进程绑定在某个 CPU 上, 防止单核过载;同时 Redis 不和 CPU 密集型应用一起部署。
- 内存。fork 内存开销,copy-on-write。
- 硬盘。AOF 和 RDB 文件的写入。可以结合 iostat 和 iotop 进行分析。
优化方法
- 不要和高硬盘负载服务部署在一起:存储服务、消息队列等
- 配置 no-appendfsync-on-rewrite=yes。这样在 AOF 重写的期间,不要进行 AOF 追加操作(主线程只将数据写入缓冲区),可以减少内存的开销。
但如果 AOF 重写期间,Redis 宕机的话,在 Linux 的系统默认配置下,最多会丢失 30s 的数据。如果无法忍受数据丢失,no-appendfsync-on-rewrite 配置 no;如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为 yes。
- 根据写入量决定磁盘类型:例如 ssd
- 单机多实例持久化文件目录可以考虑分盘,或者使用类似 cgroups 机制进行硬盘资源的合理分配
AOF 追加阻塞
例如在 AOF 的 everysec 策略中,主线程会对比上次 fsync 的时间,如果距离上次 fsync 时间超过两秒,就会造成主线程阻塞(等待同步线程同步完成)。
日常开发可以使用 info persistence
命令,查看历史发生 AOF 阻塞的次数;然而需要了解 AOF 追加阻塞的发生时间则需要查看 Redis 日志。
发送 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.
优化方法(参考其他方面的优化点)
更多内容,欢迎关注微信公众号:全菜工程师小辉~