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

用Redis来搞永久数据保存,虽然有点复杂但挺实用的办法

主要参考了Redis官方文档关于持久化的说明、以及《Redis实战》等书籍中关于数据可靠性的讨论,并结合了常见的运维实践经验)

得明确一个核心点:Redis本身的设计初衷是作为内存数据库,追求极致的速度,它的所有数据默认都放在内存里,所以一提到“永久保存”,我们实际上是在和“内存数据易失”这个天性做斗争,所谓“永久”,并不是说数据真的永不删除,而是指在服务器重启、断电等意外情况发生后,数据能够从某个地方重新加载回来,不会丢失,Redis提供了两种主要的机制来把内存里的数据写到硬盘上,从而实现这种“永久性”,它们分别是RDB和AOF。

第一种方法:RDB(快照)

你可以把RDB理解成给Redis的数据拍一张全景照片,在某个时间点,Redis会把当前内存中所有完整的数据集,以一种紧凑的、经过压缩的二进制格式 dump 到一个叫 dump.rdb 的文件里,这个文件就是你的数据快照。

怎么触发拍照呢?主要有两种方式:

  1. 自动触发:你可以在Redis的配置文件(redis.conf)里设置规则,你可以写上“save 900 1”,意思是如果在900秒(15分钟)内,至少有1个键被改变了,那就自动拍一张快照,你可以设置多个条件,像“save 300 10”(5分钟内10个键变动)、“save 60 10000”(1分钟内10000个键变动),Redis会智能地检查这些条件,满足任何一个就执行备份。
  2. 手动触发:通过连接Redis命令行,输入命令SAVE或者BGSAVESAVE会阻塞所有客户端的请求,直到快照完成为止,如果数据量很大,期间服务就不可用了,所以不常用,更常用的是BGSAVE,它会fork一个子进程在后台默默地完成快照工作,主进程继续正常提供服务,对用户基本无感。

RDB的优点很明显

  • 文件紧凑:生成的RDB文件体积小,非常适合做灾难恢复,比如你想把整个数据库迁移到另一台服务器,拷贝这个文件过去最快。
  • 恢复速度快:重启Redis时,直接把这个快照文件读回内存就行了,比另一种方法(AOF)要快得多。
  • 对性能影响小:尤其是用BGSAVE,备份过程几乎不影响主线程处理请求。

但RDB的缺点也很要命

  • 会丢数据:这是最大的问题,因为快照是定期拍的,如果还没到下一次拍照的时间,服务器突然宕机了,那么从上一次拍照到宕机之间的所有数据更新就全丢了,对于数据可靠性要求高的场景,比如计费系统,这是无法接受的。

第二种方法:AOF(追加日志)

AOF的思路和RDB完全不同,它不拍全景照,而是像写日记一样,把每一次能引起数据变化的写命令(比如SET、LPUSH、SADD)都记录下来,追加到一个文件的末尾,这个文件就是AOF日志(appendonly.aof),当Redis重启时,它会从头到尾重新执行一遍这个日志文件里的所有命令,从而精确地重建出内存数据。

用Redis来搞永久数据保存,虽然有点复杂但挺实用的办法

AOF的可靠性高多了,因为它记录了每一个操作,那它怎么控制日志文件大小和保证数据安全呢?这涉及到三个关键配置,也就是“写回策略”:

  1. appendfsync always:每处理一个写命令,就立刻将其写入AOF文件,并且强制刷到硬盘上,这是最安全的方式,基本不会丢数据(除非硬盘本身坏了),但也是速度最慢的,因为每次写入都涉及耗时的磁盘IO,会严重拖累性能。
  2. appendfsync everysec:折中的方案,每秒批量将累积的写命令同步到硬盘一次,这样最多只会丢失1秒钟的数据,在性能和可靠性之间取得了很好的平衡,是默认的推荐设置。
  3. appendfsync no:写命令只交给操作系统去决定何时刷盘,这样性能最好,但丢数据的风险也最大。

随着时间推移,AOF文件会越来越大,而且里面可能有很多重复或无效的操作(比如对一个键先后set了10次,其实只有最后一次有价值),所以Redis提供了AOF重写机制:它会fork一个子进程,根据当前数据库的数据状态,逆向生成一个全新的、最精简的AOF文件(比如一个键只保留它最终值的SET命令),然后用这个新文件替换掉臃肿的旧文件。

AOF的优点

  • 数据可靠性极高:尤其是在always策略下,几乎可以做到零数据丢失。
  • 可读性好:AOF文件是纯文本格式,里面记录着所有命令,在出问题时可以人工查看甚至修复。

AOF的缺点

  • 文件通常比RDB大
  • 恢复速度慢:如果AOF文件很大,重启后重放所有命令的过程会非常耗时。

最实用的办法:混合持久化

用Redis来搞永久数据保存,虽然有点复杂但挺实用的办法

既然RDB和AOF各有优劣,那么最实用、在生产环境中被广泛采用的,其实是结合两者的“混合持久化”,这个特性是在Redis 4.0版本引入的。

它的工作原理是: 在开启AOF功能的前提下,当执行AOF重写时,子进程不再是单纯地生成新的AOF命令日志,而是会先像RDB那样,将当前数据的快照以RDB的二进制格式写入新的AOF文件的开头,在重写过程中以及重写完成后,新产生的写命令会继续以AOF的格式追加到这个文件的后面。

这样一来,最终生成的AOF文件就变成了一锅“杂烩”:前半部分是RDB格式的全量数据,后半部分是增量数据的AOF日志

混合持久化的巨大优势

  1. 恢复速度快:重启时,Redis首先加载AOF文件中RDB格式的部分,这非常快,能迅速恢复大部分数据。
  2. 数据丢失少:紧接着,再重放后面那一小段AOF日志(从重写开始到重启前的新增命令),这样最多也就丢失重写期间几秒钟的数据(取决于你的appendfsync设置)。

这就好比你先用RDB快速恢复到一个最近的“检查点”,然后再用AOF“回放”一小段操作,就达到了既快又安全的目的,配置方法也很简单,在redis.conf中同时开启appendonly yesaof-use-rdb-preamble yes即可。

总结一下: 想用Redis搞永久数据保存,别单打一。首选“RDB定期备份 + AOF每秒刷盘 + 开启混合持久化”这个组合拳,用RDB做冷备和快速恢复的基石,用AOF保证数据的实时安全性,再用混合持久化来兼顾恢复速度和数据完整性,为了万无一失,最好还能定期把RDB文件或者AOF文件拷贝到别的机器上做异地备份,这样就算整个机房出问题,也能把数据找回来。