Redis,是目前,最流行的,内存数据库。它,性能,高,延迟,低,数据结构,丰富,广泛,应用于,缓存,会话存储,消息队列,排行榜,实时统计,等,场景。

但是,Redis,是,内存数据库。数据,都,存在,内存里。一旦,进程,退出,或者,服务器,宕机,内存里的,数据,就,会,丢失。

为了,解决,这个,问题,Redis,提供了,持久化,机制。把,内存里的,数据,保存到,磁盘上。这样,即使,进程,退出,或者,服务器,宕机,数据,也,不会,丢失。重启,之后,Redis,会,从,磁盘,加载,数据,恢复到,之前的,状态。

Redis,提供了,两种,持久化,方式:RDB,和,AOF。

我,用Redis,已经,三年多了。这三年,在,Redis持久化,方面,踩了,不少,坑,也,积累了,一些,经验。今天,想,分享一下,我,对Redis持久化的,理解,和,感悟。

希望,这些,经验,能,帮,大家,更好地,使用Redis,避免,踩坑。

一、RDB:快照持久化

先,说说,RDB。

RDB,是,Redis Database的,缩写。它,是,一种,快照,持久化,方式。

简单来说,RDB,就是,在,某个,时间点,把,Redis,内存里的,所有数据,生成,一个,快照,保存到,磁盘上。这个,快照文件,通常,叫,dump.rdb。

RDB,的,触发,方式,有,两种:手动触发,和,自动触发。

手动触发,有,两个,命令:

  • save:同步,生成,RDB快照。执行,这个,命令,的时候,Redis,会,阻塞,直到,快照,生成,完成。在,这期间,Redis,不能,处理,其他,请求。所以,一般,不建议,在,生产环境,用,这个,命令。
  • bgsave:异步,生成,RDB快照。执行,这个,命令,的时候,Redis,会,fork,一个,子进程,来,生成,快照。父进程,继续,处理,请求,不会,阻塞。所以,生产环境,一般,用,这个,命令。

自动触发,就是,在,配置文件,里,配置,save规则。比如:

save 900 1
save 300 10
save 60 10000

这,三行,配置,的,意思,是:

  • 900秒,内,有,1个,key,发生了,变化,就,自动,触发,bgsave。
  • 300秒,内,有,10个,key,发生了,变化,就,自动,触发,bgsave。
  • 60秒,内,有,10000个,key,发生了,变化,就,自动,触发,bgsave。

只要,满足,其中,任意,一条,规则,就,会,自动,触发,bgsave,生成,RDB快照。

RDB,的,优点:

  1. 文件,紧凑:RDB文件,是,经过,压缩的,二进制,文件,体积,比较,小。适合,备份,和,迁移。
  2. 恢复,快:RDB,是,直接,把,内存,数据,序列化,保存的。恢复的时候,直接,加载,到,内存,就,可以了。恢复速度,比,AOF,快。
  3. 对,性能,影响,小:RDB,是,用,子进程,生成,快照的。对,父进程,的,性能,影响,比较,小。

RDB,的,缺点:

  1. 数据,可能,丢失:RDB,是,间隔,一段时间,生成,一次,快照。如果,在,两次,快照,之间,Redis,宕机了,那么,这,期间,的数据,就,会,丢失。
  2. fork,子进程,开销大:每次,生成,RDB快照,都,要,fork,一个,子进程。如果,数据量,很大,fork,的,过程,可能,会,比较,耗时,也,会,占用,比较,多的,内存。在,数据量,很大的,情况下,可能,会,导致,Redis,短暂,卡顿。

二、AOF:追加持久化

再,说说,AOF。

AOF,是,Append Only File的,缩写。它,是,一种,追加,持久化,方式。

简单来说,AOF,就是,把,Redis,执行的,每一条,写命令,都,记录,下来,追加到,AOF文件,里。这样,Redis,重启,的时候,就,可以,重新,执行,AOF文件,里的,所有,命令,来,恢复,数据。

AOF,默认,是,关闭的。要,开启,需要,在,配置文件,里,设置:

appendonly yes

开启,之后,Redis,会,生成,一个,AOF文件,通常,叫,appendonly.aof。

AOF,有,三种,刷盘,策略:

  1. always:每,执行,一条,写命令,就,刷一次,盘。这种,方式,最,安全,数据,几乎,不会,丢失。但是,性能,最差,因为,每次,写,都,要,刷盘,IO开销,大。
  2. everysec:每秒,刷一次,盘。这是,默认的,策略。这种,方式,是,性能,和,安全,的,折中。最多,丢失,一秒的,数据。
  3. no:不,主动,刷盘,由,操作系统,决定,什么时候,刷盘。这种,方式,性能,最好,但是,最,不安全。如果,服务器,宕机,可能,会,丢失,比较,多的,数据。

一般,推荐,用,默认的,everysec,策略。性能,和,安全,都,比较,适中。

AOF,还有,一个,重要的,机制,叫,AOF重写。

因为,AOF,是,追加,写命令的。时间,长了,AOF文件,会,越来越,大。而且,里面,可能,有,很多,冗余的,命令。比如,对,同一个,key,执行了,100次,set,其实,最后,只,需要,最后,一次,set,的,结果,就,可以了。前面,99次,都是,冗余的。

所以,Redis,提供了,AOF重写,机制。AOF重写,会,重新,生成,一个,新的,AOF文件,里面,只,保留,恢复,数据,所,必需的,最小,命令集。这样,AOF文件,的,体积,就,会,小,很多。

AOF重写,也,有,两种,触发,方式:

  • 手动触发:执行,bgrewriteaof,命令。
  • 自动触发:根据,配置,的,规则,自动,触发。比如,auto-aof-rewrite-percentage 100,和,auto-aof-rewrite-min-size 64mb。意思,是,当,AOF文件,的,体积,比,上次,重写,后,增长了,100%,并且,体积,超过了,64MB,就,自动,触发,AOF重写。

AOF,的,优点:

  1. 数据,安全:AOF,是,每,秒,刷一次,盘。最多,丢失,一秒的,数据。比,RDB,安全,很多。
  2. 文件,可读:AOF文件,是,文本,格式的,里面,记录的,是,Redis,命令。可以,直接,打开,查看,也,可以,手动,修改。
  3. 重写,机制:AOF,有,重写,机制,可以,自动,压缩,AOF文件,去除,冗余,命令。

AOF,的,缺点:

  1. 文件,大:AOF文件,通常,比,RDB文件,大。因为,它,记录的,是,命令,不是,数据快照。
  2. 恢复,慢:AOF,恢复,的时候,需要,重新,执行,所有,命令。如果,AOF文件,很大,恢复,速度,会,比较,慢。
  3. 可能,有,bug:AOF,记录的,是,命令。如果,某些,命令,有,bug,可能,会,导致,恢复,的时候,出问题。虽然,这种,情况,很少,但是,理论上,是,存在的。

三、我踩过的,那些,坑

介绍完,RDB,和,AOF,的,基本,原理,再,说说,我,这三年,在,Redis持久化,方面,踩过的,那些,坑。

坑一:只用RDB,结果,丢了,不少,数据

刚,开始,用Redis,的时候,我,对,持久化,不太,懂。看了,一下,默认,配置,发现,RDB,默认,是,开启的,AOF,默认,是,关闭的。我,就,以为,默认,配置,就是,最好的,就,直接,用了,默认,配置。

结果,有一次,服务器,突然,宕机了。重启,之后,Redis,从,RDB,恢复,数据。但是,我,发现,最近,几个小时的,数据,都,丢了。

因为,RDB,是,间隔,一段时间,生成,一次,快照。上次,快照,是,几个小时,前,生成的。这,几个小时,的,数据,都,没来得及,生成,快照,就,丢了。

那次,丢数据,给,我们,造成了,不小的,影响。后来,我们,才,知道,RDB,的,数据,安全性,不够。对于,不能,丢数据的,场景,应该,开启,AOF。

从那以后,我们,所有的,Redis实例,都,开启了,AOF。

坑二:AOF文件,太大,导致,磁盘,满了

开启了,AOF,之后,数据,安全,了,很多。但是,又,遇到了,新的,问题。

有一次,我们,发现,一台,Redis服务器,的,磁盘,使用率,突然,飙升,很快,就,到了,90%,以上。

我们,赶紧,排查,发现,是,AOF文件,太大了。那个,实例,的,写操作,很,频繁,AOF文件,增长,得,很快。而且,AOF重写,的,配置,不太,合理,没有,及时,触发,重写。导致,AOF文件,越来越,大,最后,把,磁盘,占满了。

磁盘,满了,之后,Redis,没法,写,AOF文件,了,也,没法,正常,工作了。我们,赶紧,清理,磁盘,手动,触发,AOF重写,才,解决了,问题。

那次,事件,之后,我们,调整了,AOF重写,的,配置,让,它,能,更,及时,地,触发,重写。而且,我们,也,加了,磁盘,使用率,的,监控,和,告警。一旦,磁盘,使用率,超过,阈值,就,告警,及时,处理。

坑三:fork,子进程,导致,Redis,卡顿

还有一次,我们,有一个,数据量,很大的,Redis实例,内存,用了,差不多,50GB。

每次,生成,RDB快照,或者,AOF重写,的时候,都,要,fork,一个,子进程。因为,数据量,大,fork,的,过程,比较,耗时。而且,fork,之后,子进程,和,父进程,共享,内存页。如果,这期间,父进程,有,很多,写操作,就,会,触发,写时复制(COW),占用,额外的,内存。

那段时间,每次,生成,RDB,或者,AOF重写,的时候,Redis,就,会,短暂,卡顿。请求,延迟,明显,上升,甚至,有,一些,请求,超时。

我们,排查了,很久,才,发现,是,fork,子进程,导致的。

后来,我们,做了,一些,优化:

  1. 调整,RDB,的,save规则,减少,生成,RDB,的,频率。
  2. 调整,AOF重写,的,配置,避免,频繁,重写。
  3. 把,这个,大实例,拆分成,多个,小实例,降低,单个,实例,的,数据量。
  4. 开启,disable-thp,关闭,透明大页,减少,fork,的,开销。

经过,这些,优化,卡顿,的,问题,才,得到了,缓解。

坑四:AOF恢复,太慢,影响,上线

还有一次,我们,有一个,Redis实例,需要,重启。因为,AOF文件,很大,有,好几个GB。重启,之后,加载,AOF,恢复,数据,花了,很长,时间,差不多,半个多小时。

这,半个多小时,这个,实例,没法,提供,服务。对,业务,造成了,不小的,影响。

后来,我们,才,知道,AOF恢复,的,速度,比,RDB,慢,很多。因为,AOF,需要,重新,执行,所有,命令。而,RDB,是,直接,加载,数据。

从那以后,我们,对于,数据量,大的,实例,会,同时,开启,RDB,和,AOF。恢复,的时候,优先,用,RDB,恢复,因为,快。然后,再,用,AOF,补充,RDB,之后的,数据。

而且,我们,也,会,定期,手动,触发,RDB,和,AOF重写,保证,RDB文件,和,AOF文件,不会,太旧,太大。

四、我总结的,经验教训

踩了,这么多,坑,我,也,总结了,一些,经验教训。

1. 根据,场景,选择,合适的,持久化,方式

不是,所有的,场景,都,需要,同样的,持久化,方式。

如果,Redis,只是,用来,做,缓存,数据,丢了,也,没关系,可以,从,数据库,重新,加载。那么,甚至,可以,不用,持久化,或者,只用,RDB,就,够了。

如果,Redis,用来,存储,重要的,数据,不能,丢。那么,一定要,开启,AOF,保证,数据,安全。

如果,对,数据,安全,要求,很高,而且,也,希望,恢复,快。那么,可以,同时,开启,RDB,和,AOF。两者,结合,用,既,安全,又,能,快速,恢复。

2. 合理,配置,RDB,的,save规则

RDB,的,save规则,要,根据,业务,的,特点,合理,配置。

如果,写操作,很,频繁,数据,变化,快。那么,save规则,可以,设置得,密一点,减少,数据,丢失的,风险。

如果,写操作,很少,数据,变化,慢。那么,save规则,可以,设置得,疏一点,减少,生成,RDB,的,频率,降低,对,性能,的,影响。

而且,要,注意,不要,设置,太,激进的,save规则。比如,save 60 10000,如果,写操作,很,频繁,可能,会,频繁,触发,bgsave,影响,性能。

3. 开启,AOF,用,everysec,策略

对于,需要,AOF,的,场景,推荐,开启,AOF,并且,用,默认的,everysec,刷盘,策略。

always,太,慢,性能,差,一般,不推荐,除非,对,数据,安全,要求,极高。

no,太,不安全,可能,丢,很多,数据,也,不推荐。

everysec,是,性能,和,安全,的,最佳,折中。最多,丢,一秒的,数据,性能,也,不错。

4. 合理,配置,AOF重写

AOF重写,的,配置,也,很,重要。

auto-aof-rewrite-percentage,和,auto-aof-rewrite-min-size,这,两个,参数,要,合理,设置。

如果,设置得,太,宽松,AOF文件,可能,会,很大,才,触发,重写。导致,AOF文件,占用,太多,磁盘,空间。

如果,设置得,太,激进,可能,会,频繁,触发,AOF重写,影响,性能。

一般,默认的,100%,和,64MB,就,比较,合适。可以,根据,具体,情况,调整。

5. 监控,磁盘,使用率

一定要,监控,Redis服务器,的,磁盘,使用率。

RDB文件,和,AOF文件,都会,占用,磁盘,空间。如果,不,监控,可能,会,出现,磁盘,满了,的,情况,导致,Redis,没法,正常,工作。

建议,设置,磁盘,使用率,的,告警。比如,超过,80%,就,告警。及时,清理,旧的,备份文件,或者,手动,触发,AOF重写,压缩,AOF文件。

6. 大内存,实例,注意,fork,开销

对于,内存,使用量,很大的,Redis实例,要,特别,注意,fork,子进程,的,开销。

生成,RDB,和,AOF重写,都,需要,fork,子进程。数据量,越大,fork,的,开销,越大,可能,会,导致,Redis,短暂,卡顿。

对于,大内存,实例,建议:

  1. 减少,生成,RDB,和,AOF重写,的,频率。
  2. 考虑,拆分成,多个,小实例。
  3. 关闭,透明大页(THP)。
  4. 合理,配置,maxmemory,和,淘汰,策略。

7. 定期,备份,和,演练,恢复

最后,一定要,定期,备份,Redis,的,数据,并且,演练,恢复,流程。

不要,以为,开了,持久化,就,万事大吉了。持久化,文件,也,可能,损坏,也,可能,丢失。

所以,要,定期,把,RDB文件,或者,AOF文件,备份,到,其他,地方。比如,其他,服务器,或者,云存储。

而且,要,定期,演练,恢复,流程。确保,备份,的,文件,是,好的,能,正常,恢复,数据。不要,等到,真的,出了,问题,才,发现,备份,用不了。

五、写在最后

用了,三年,Redis持久化,踩了,不少,坑,也,学到了,很多。

Redis持久化,看起来,简单,不就是,RDB,和,AOF,吗?但是,真正,用起来,才,发现,里面,有,很多,细节,和,坑。

只有,真正,理解了,RDB,和,AOF,的,原理,优缺点,适用场景,才能,合理地,配置,和,使用,避免,踩坑。

希望,我,的,这些,经验,和,教训,能,帮,大家,更好地,使用Redis持久化,少走弯路。

如果你,也,有,Redis持久化,的,经验,或者,踩过的,坑,欢迎,在,评论区,留言,我们,一起,交流。