当前位置:首页 > 问答 > 正文

Redis快照机制那些事儿,缓存安全到底咋保障的呢?

Redis这个高性能的缓存和内存数据库,大家肯定不陌生,它之所以能这么快,核心就在于所有数据都放在内存里操作,但内存有个硬伤:一断电,数据就全没了,这显然不行,万一服务器突然宕机,所有缓存数据瞬间蒸发,对业务来说就是一场灾难,Redis设计了一套持久化机制,把内存里的数据定期存到硬盘上,相当于给数据拍个“快照”,这样即使Redis进程重启,也能从硬盘上的快照文件恢复数据,保证数据不会丢得那么彻底,这个“拍快照”的过程,就是我们要说的RDB持久化,也就是Redis的快照机制。

Redis快照是怎么工作的?

简单说,快照就是Redis在某个时间点,把当前内存中所有数据的完整副本,一次性、序列化之后保存到一个叫dump.rdb的二进制文件中,这个文件就像是Redis数据的一个备份照片。

什么时候会触发拍这张“照片”呢?主要有两种方式,根据“Redis设计与实现”这本书以及官方文档的说明:

  1. 手动触发:运维人员可以通过在Redis命令行里执行SAVEBGSAVE命令来立即创建快照。

    • SAVE命令:这个命令会阻塞Redis的主线程,意思是,在执行SAVE期间,Redis不能处理任何其他的读写请求,整个服务会卡住,直到整个快照文件创建完毕,如果数据量很大,这个卡顿时间可能会很长,所以在生产环境几乎不用。
    • BGSAVE命令:这个命令是后台异步执行的,Redis主进程会fork出一个子进程(fork是操作系统的一个操作,可以创建一个和父进程一模一样的子进程),由这个子进程去负责将内存数据写入RDB文件,而父进程(主线程)可以继续正常地处理客户端的命令请求,服务不会中断,这是我们最常用的方式。
  2. 自动触发:这是生产环境的主流配置,我们可以在Redis的配置文件redis.conf里设置一些规则,让Redis自动在后台执行BGSAVE,规则看起来像这样: save 900 1 # 在900秒(15分钟)内,如果至少有1个key发生了变化 save 300 10 # 在300秒(5分钟)内,如果至少有10个key发生了变化 save 60 10000 # 在60秒(1分钟)内,如果至少有10000个key发生了变化 只要满足其中任意一个条件,Redis就会自动发起一个BGSAVE操作。

快照机制的优点和软肋

这个机制好处很明显:

  • 性能影响小:由于BGSAVE是子进程在后台操作,避免了服务停顿,对读写性能影响非常有限。
  • 适合灾难恢复:RDB文件是一个完整的压缩过的二进制文件,非常适合用来做灾难备份,你可以定时把dump.rdb文件拷贝到别的安全的地方,比如远程服务器或者云存储上。
  • 恢复速度快:当Redis重启时,直接加载RDB文件到内存,比另一种持久化方式(AOF,后面会提)的恢复速度要快得多。

它的软肋也极其致命,这正是“缓存安全”问题的核心所在:

Redis快照机制那些事儿,缓存安全到底咋保障的呢?

  • 可能丢失较多数据:这是快照最大的风险,因为快照是定期拍的,比如你设置的是5分钟拍一次,那么如果服务器在最后一次成功拍快照的4分59秒时突然宕机,那么这5分钟内写入的所有新数据就全部丢失了,对于数据一致性要求高的业务(比如订单、支付),这是无法接受的。

光靠快照不够,如何更安全地保障数据?

正因为RDB快照有数据丢失的风险,Redis提供了另一种更安全的持久化方式:AOF(Append Only File,追加日志文件),根据Redis官方文档的描述,AOF的理念完全不同,它不是拍照片,而是记日记

AOF会把Redis服务器执行过的每一个写命令(比如SET, HSET, SADD等)都记录到一个日志文件里,每执行一个写命令,就把这个命令追加到AOF文件的末尾,这样,当Redis重启时,它会从头到尾重新执行一遍AOF文件里记录的所有写命令,从而精确地还原到宕机前的数据状态。

如果同时开启AOF和RDB,Redis在重启时会优先使用AOF文件来恢复数据,因为AOF通常保存了更完整的数据。

AOF的“日记”可以配置不同的“记法”,也就是不同的刷盘策略,这直接关系到安全性和性能的权衡:

Redis快照机制那些事儿,缓存安全到底咋保障的呢?

  • appendfsync always:每个写命令都立刻同步到硬盘,这是最安全的,数据基本不会丢(除非硬盘坏了),但性能也是最差的,因为每次写操作都要等硬盘IO。
  • appendfsync everysec:每秒同步一次,这是默认的推荐配置,算是一个折中方案,即使宕机,最多丢失1秒钟的数据,性能比always好很多。
  • appendfsync no:让操作系统来决定何时同步,性能最好,但丢数据的风险最大。

最佳实践:混合持久化

有没有办法既享受RDB快速恢复的好处,又拥有AOF数据更安全的保障呢?在Redis 4.0版本之后,引入了混合持久化的功能。

开启这个功能后,当Redis执行BGSAVE快照时,这个快照操作会变成:首先依然fork子进程生成一个RDB格式的数据快照,在快照生成之后,在这个RDB数据内容的后面,Redis会再追加一个AOF格式的日志,这个日志记录的是从快照开始到快照结束这段时间内,主线程新接收到的所有写命令。

这样最终生成的是一个同时包含RDB数据和增量AOF日志的文件,当Redis重启时,它会先加载RDB部分的内容(恢复基础数据),然后再重演后面追加的AOF命令(恢复增量数据),这样一来,恢复速度很快(因为大部分数据是RDB格式),同时数据丢失的量也仅仅是从最后一次快照开始到宕机那一刻的AOF日志量,通常非常短。

总结一下

回到“缓存安全到底咋保障”这个问题,答案不是单一的:

  1. 如果可以容忍几分钟的数据丢失,比如只是用来缓存一些不那么关键的热点数据,那么只使用RDB快照机制可能就足够了,因为它简单高效。
  2. 如果对数据安全性要求很高,绝对不能丢数据,那么你必须开启AOF持久化,并至少使用everysec配置。
  3. 为了达到性能和安全的极致平衡,在Redis 4.0+的环境中,强烈建议开启混合持久化,它结合了RDB和AOF的优点,是目前保障Redis缓存数据安全的最佳实践之一。

最最安全的办法是“不要把鸡蛋放在一个篮子里”,无论采用哪种持久化策略,定期将RDB或AOF文件备份到不同的物理机、机房或云存储上,才是应对真正灾难(比如服务器硬盘彻底损坏)的终极保障。