666按常理来说,应该介绍下什么是Redis,按照从入门到进阶的思路嘛,但这里就免了,我假设读者都了解Redis,起码知道它是干什么用的。
那直接进入正题,从一个面试题入手“Redis重启后数据会丢失吗?”
很傻的问题,不过作为面试官的我昨天就问过某个面试者,答:“不会,数据还在”,那做我就会继续问了“它数据还在?是什么机制能让数据不会丢失呢?它不是内存数据库吗?”
答:“呃,好像是做了持久化,使用binlog吧”
好了,这问题已经谈不下去了,而且这个问题答不上来的不只一两个,怎么办? 写个文章聊聊呗
其实Redis保证重启后数据不丢失的原因确实是做了持久化,但持久化是使用RDB,和AOF两种策略来实现的,那接下来的分析我也分这两部分进行。
1.1. RDB到底是什么
RDB 是 Redis 默认的持久化方案。在指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中。即在指定目录下生成一个dump.rdb文件。Redis 重启会通过加载dump.rdb文件恢复数据。
很好理解,也就是我什么都不做,RDB就是可以用的了,在配置文件里面又怎么体现的呢?
你找到配置文件,在配置redis.conf文件里面找下如下的配置
save 60 1000
这个配置指的是,每隔60s,如果有超过1000个key发生了变更,那么就生成一个新的dump.rdb文件,就是当前redis内存中完整的数据快照,这个操作也被称之为snapshotting,快照
当然你也可以手动调用save或者bgsave命令,同步或异步执行rdb快照生成,同时save可以设置多个,就是多个snapshotting检查点,每到一个检查点,就会去check一下,是否有指定的key数量发生了变更,如果有,就生成一个新的dump.rdb文件
1.1.1. RDB工作流程
上面画了个简单的图,描绘的是RDB持久化机制的工作流程,具体来看可以有如下几个步骤
(1)redis根据配置自己尝试去生成rdb快照文件
(2)fork一个子进程出来
(3)子进程尝试将数据dump到临时的rdb快照文件中
(4)完成rdb快照文件的生成之后就替换之前的旧的快照文件dump.rdb,每次生成一个新的快照,都会覆盖之前的老快照
这是RDB的整个流程,根据图的描述假设早上6点整触发了一次RDB,当6点过1分的时候,如果数据量到2000,会触发一次RDB,生成新的快照文件。一切都这么好。
,假设有这种情况,如果在6的时候触发了一次RDB,在6点过1分的时候,数据还只有1900,按条件是不会触发RDB的,那么问题来了,这时候突然Redis服务器down机,会出现什么问题呢?
你猜对了,900条数据会整个丢失,那怎么解决呢?你可能会想这个不难,既然save 60 1000不会好,数据会丢失,而且save检查点是可以设置多个的,我save 1 1 不就好了吗,一秒内如果有1条数据变化了,我触发一次RDB,这样数据就不会丢了。
想法是好的,但现实是骨感的,这RDB是快照文件,里面存放的是全量的数据库数据,你一秒就执行一次RDB,你觉得性能吃得消嘛? 这肯定是个特别糟糕的解决方式,怎么办呢?你需要AOF这种持久化策略,但别着急,先来总结以下RDB的优缺点
1.1.2. RDB优缺点总结
RDB持久化机制的优点
1 适合大规模的数据恢复,尤其擅长冷备
2 如果业务对数据完整性和一致性要求不高,RDB是很好的选择
RDB持久化机制的缺点
1 数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。
2 备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍哦),最后再将临时文件替换之前的备份文件。
所以Redis 的持久化和数据的恢复要选择在夜深人静的时候执行是比较合理的。
1.2. AOF又是什么鬼
前面已经知道RDB是什么东西了,RDB在保证性能的前提下可能会数据丢失,那接下来就应该聊聊AOF了,AOF是什么呢?
AOF :Redis 默认不开启。它的出现是为了弥补RDB的不足(数据的不一致性),所以它采用日志的形式来记录每个写操作,并追加到文件中。Redis 重启的会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
也好理解,它记录的是日志文件,显然速度应该快很多,但是默认却是关闭的,怎么开启呢?
找到配置文件后,你需要修改的第一个配置为
appendonly yes
以打开AOF持久化机制,在生产环境里面,一般来说AOF都是要打开的,除非你说随便丢个几分钟的数据也无所谓
打开AOF持久化机制之后,redis每次接收到一条写命令,就会写入日志文件中,当然是先写入os cache的,然后每隔一定时间再fsync一下磁盘文件
这里有一个问题了,如果AOF和RDB都开启了,Redis重启了以谁为准呢?
答案是:redis重启的时候,也是优先通过AOF进行数据恢复的,因为aof数据比较完整
除开appendonly的这个配置项,关于AOF还有一个非常有意思的配置
appendfsync everysec
这个appendfsync 默认值是everysec,除开这个以外,总共有3个取值的可能
always: 每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常非常差,吞吐量很低; 确保说redis里的数据一条都不丢,那就只能这样了
everysec: 每秒将os cache中的数据fsync到磁盘,这个最常用的,生产环境一般都这么配置,性能很高,QPS还是可以上万的
no: 仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控了
可见默认值就是最好的选项了。
1.2.1. AOF工作流程
下面有个简图,描绘的是AOF的工作流程
(1)redis fork一个子进程
(2)子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写入日志
(3)redis主进程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件
(4)子进程写完新的日志文件之后,redis主进程将内存中的新日志再次追加到新的AOF文件中
(5)用新的日志文件替换掉旧的日志文件
可见AOF很好解决了RDB数据丢失的问题,下面再来看下AOF的文件的优缺点
1.2.2. AOF优缺点总结
AOF持久化机制的优点
数据的完整性和一致性更高
AOF持久化机制的缺点
因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢
1.3. 总结
最后我们再来总结以下,关于RDB,AOF两种持久化策略的特点
Redis 默认开启RDB持久化方式,在指定的时间间隔内,执行指定次数的写操作,则将内存中的数据写入到磁盘中。
RDB 持久化适合大规模的数据恢复但它的数据一致性和完整性较差。
Redis 需要手动开启AOF持久化方式,默认是每秒将写操作日志追加到AOF文件中。
AOF 的数据完整性比RDB高,但记录内容多了,会影响数据恢复的效率。
Redis 针对 AOF文件大的问题,提供重写的瘦身机制。
若只打算用Redis 做缓存,可以关闭持久化。
若打算使用Redis 的持久化。建议RDB和AOF都开启。其实RDB更适合做数据的备份,留一后手。AOF出问题了,还有RDB。
**