美团面试原题:利用Redis的持久化机制有效避免数据丢失:技巧与最佳实践

Redis持久化机制的重要性

Redis的持久化机制是后端面试中一个极为常见的知识点,值得深入学习和掌握。即便你不是在为面试做准备,这些知识在日常开发中也会频繁用到。

缓存与数据持久化

在使用缓存时,我们常常需要将内存中的数据持久化,以便在机器重启或故障时能够恢复数据,或进行数据同步(例如,Redis集群的主从节点通过RDB文件进行数据同步)。

Redis与Memcached的一个显著区别在于,Redis支持持久化,并提供三种持久化方式:

  • 快照(Snapshotting,RDB)
  • 只追加文件(Append-Only File,AOF)
  • RDB与AOF的混合持久化(新增于Redis 4.0)

官方文档链接:Redis持久化

RDB持久化详解

RDB持久化的定义

Redis通过创建快照来获取内存中数据在某个特定时间点的副本。创建快照后,可以将其备份并复制到其他服务器,进而构建数据相同的服务器副本(适用于Redis的主从结构),这主要用于提高Redis的性能。

快照持久化是Redis默认的持久化方式。以下是redis.conf配置文件中的默认设置:

save 900 1          # 在900秒内,如果至少有1个key发生变化,Redis将自动触发bgsave命令创建快照。
save 300 10         # 在300秒内,如果至少有10个key发生变化,Redis将自动触发bgsave命令创建快照。
save 60 10000       # 在60秒内,如果至少有10000个key发生变化,Redis将自动触发bgsave命令创建快照。

RDB快照是否会阻塞主线程?

Redis提供两种命令来生成RDB快照文件:

  • save: 同步保存操作,会阻塞Redis的主线程;
  • bgsave: 通过创建子进程来执行,不会阻塞Redis的主线程,这是默认选项。

AOF持久化详解

AOF持久化的定义

相较于快照持久化,AOF(Append-Only File)持久化的实时性更强。Redis在默认情况下并未开启AOF持久化(在Redis 6.0及之后版本中,默认已开启),可以通过appendonly参数进行配置:

appendonly yes

开启AOF持久化后,每次执行更改Redis中数据的命令,Redis会将该命令写入AOF缓冲区server.aof_buf,然后再写入AOF文件(此时仍在系统内核缓存区中,尚未同步到磁盘)。

只有在数据同步到磁盘后,才算持久化保存,否则存在数据丢失的风险,例如:如果系统内核缓存区的数据尚未同步,而磁盘故障发生,则这部分数据将丢失。

AOF文件的保存位置与RDB文件相同,通过dir参数设置,默认文件名为appendonly.aof

AOF工作流程

AOF持久化功能的基本流程如下:

  1. 命令追加(Append):所有写命令会被追加至AOF缓冲区。
  2. 文件写入(Write):将AOF缓冲区的数据写入AOF文件中。此时调用write函数(系统调用),并将数据写入系统内核缓冲区后直接返回(延迟写)。注意,此时并未同步至磁盘。
  3. 文件同步(Fsync):根据持久化方式(fsync策略),AOF缓冲区向硬盘进行同步操作。此步骤需要调用fsync函数(系统调用),确保磁盘写入操作完成后返回,确保数据持久化。
  4. 文件重写(Rewrite):随着AOF文件逐渐增大,需要定期对AOF文件进行重写,以达到压缩目的。
  5. 重启加载(Load):当Redis重启时,可以加载AOF文件进行数据恢复。

AOF持久化方式

在Redis的配置文件中,有三种不同的AOF持久化方式(fsync策略):

  1. appendfsync always:主线程调用write执行写操作后,后台线程立即调用fsync,这种方式会显著降低Redis性能。
  2. appendfsync everysec:主线程调用write执行写操作后立即返回,后台线程每秒调用一次fsync同步AOF文件。
  3. appendfsync no:主线程调用write执行写操作后立即返回,让操作系统决定同步时机。

为了兼顾数据安全性和写入性能,可以选择appendfsync everysec选项,使Redis每秒同步一次AOF文件,性能影响较小,且即使发生系统崩溃,用户最多只会丢失一秒内产生的数据。

从Redis 7.0.0开始,Redis引入了Multi Part AOF机制,将原来的单一AOF文件拆分为多个AOF文件。

AOF日志记录机制

Redis的AOF持久化机制在执行命令后记录日志,目的是避免额外的检查开销,且不会阻塞命令执行。虽然这种方式存在风险,比如刚执行完命令后Redis宕机可能导致相应的修改丢失,但从整体性能来看,AOF持久化方式依然得到了广泛应用。

AOF重写机制

当AOF文件过大时,Redis可以在后台自动重写AOF,生成一个新的AOF文件,其状态与原AOF文件一致,但体积更小。重写过程在子进程中执行,同时AOF重写缓冲区会记录所有写命令,确保最终新文件的状态与现有状态一致。

AOF校验机制

AOF校验机制用于在Redis启动时检查AOF文件的完整性,通过使用CRC64算法计算校验和来判断文件是否损坏,确保数据的可靠性。

Redis持久化机制的优化与选择

Redis 4.0及之后版本支持RDB与AOF的混合持久化,结合两者的优点,能够更快速地加载数据并避免数据丢失。

在选择RDB与AOF时,可以根据具体需求决定:

  • 如果数据丢失影响不大,使用RDB;
  • 不建议单独依赖AOF,定期创建RDB快照以便备份;
  • 如果数据安全性要求较高,建议同时开启RDB与AOF或者选择混合持久化。

参考资料

[1] Redis 7.0 Multi Part AOF 的设计和实现: https://zhuanlan.zhihu.com/p/467217082

[2] Redis 的 AOF 方式 #783: https://github.com/Snailclimb/JavaGuide/issues/783

[3] Redis AOF 重写描述不准确 #1439: https://github.com/Snailclimb/JavaGuide/issues/1439

[4] Redis persistence: https://redis.io/docs/manual/persistence/