Redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到硬盘中来保证持久化。
Redis支持的两种持久化方式
1.RDB(snapshotting快照)
也是默认方式。(把数据做一个备份,将数据存储到文件)
快照是默认的持久化方式,这种方式是将内存中数据以快照的方式写到二进制文件中,默认的文件名为dump.rdb。
数据库快照原理就是将整个Redis内存中的所有的数据遍历一遍存储到一个扩展名为rdb的数据文件中,通过save命令可以调用这个过程。
# 在多长时间内,有多少次更新操作,就把数据同步到数据文件中。
Save 900 1 # 900秒内,有一次更新操作,就触发同步操作
Save 300 10
Save 60 10000
RDB持久化机制的工作流程
- redis根据配置尝试去生成rdb快照文件
- fork一个子进程出来
- 子进程尝试将数据dump到临时的rdb快照文件中
- 替换旧rdb文件
dump.rdb,每次生成一个新的快照,都会覆盖之前的老快照。
2.AOF(Append onlyfile)
由于rdb方式是在一定时间间隔做一次快照的,所以如果redis crash的话,就会丢失最后一次快照后的所有修改。
aof比rdb有更好的持久化性,在使用aof时,redis会将每一个收到的写命令都通过write函数追加到文件中,当redis重启时会通过重新执行文件中保存的写命令来在内存中重新构建整个数据库。
当然,aof出于性能的考虑,不会每个write命令都落盘,它会先将命令写到内核的文件系统缓存中,再由一定的条件,刷到磁盘上。这样的aof方式的持久化也还是有可能丢失部分修改的。
可以修改配置文件来觉得缓存 落盘的触发条件:
Appendfsync no/always/everysec
# no 表示由操作系统决定何时落盘,性能最好,持久化没保障
# Always 每次更新操作 相关的缓存都落盘,性能差,但是能保证数据不丢失
# Everysec 表示每秒落盘一次
AOF rewrite
由于Redis的淘汰策略(LRU)的存在,有可能AOF文件中很多数据,在Redis中已经删掉了。这样的话,就会造成AOF文件越来越臃肿。
所以AOF每隔一段时间会做rewrite操作,基于目前数据库的状态,重新构建日志,覆盖旧日志。
rewrite工作流程
- fork一个子进程
- 子进程基于目前数据库的状态,构建日志,开始往一个新的AOF文件中写入日志
- master进程在收到新的写操作之后,在内存中写入日志(同时新的日志也会继续写入旧的AOF文件)
- 子进程写完新的日志文件之后,master进程会将内存中的新日志再次追加到新的AOF日志中
- 替换旧日志文件
RDB的问题
Redis有两种存储方式,默认是snapshot方式,实现方法是定时将内存的快照(snapshot)持久化到硬盘,这种方法缺点是持久化之后如果出现crash则会丢失一段数据。
AOF的问题
在一个并发更改上完的系统中,你要确保数据不丢失,只能将AOF日志落盘的时间间隔调短,这将会有以下问题:
- 命令日志变得非常庞大,管理维护成本非常高
- 落盘次数多,影响性能
- 恢复重建时间会非常长
redis这种内存型数据库其优势主要在于“快快快”,而AOF主要目的是“可靠、高可用、性能差”,这样就看出AOF是一个非常不协调的部分
RDB和AOF该如何选择
(1)不要仅仅使用RDB,那样crash的时候会导致你丢失数据
(2)也不要仅仅使用AOF,通过AOF做冷备没有用RDB做冷备恢复的速度快
(3)综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择;用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复
另外,要注意的是:如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制