通常情况下redis的数据全部存储在内存中,数据库一旦故障发生重启数据会全部丢失,即使是在redis cluster或者redis sentinel模式下主从同步数据的恢复仍然需要一段时间。
持久化功能在于能够有效地避免因进程退出造成的数据丢失问题,在下次重启时利用之前持久化的文件即可实现数据恢复。
开启Redis持久化之后,数据将存放到磁盘中,数据库执行增量同步的时间要远小于全量同步。在生产环境下故障的数据恢复有着非常重要的作用!
Redis持久化有两种方案:
RDB是一种快照式的数据存储,它会周期性的保存当前时间点Redis所有的数据到磁盘中。 AOF是一种追加式的存储方式,会实时的记录Redis的写操作到磁盘中。
RDB持久化把当前进程数据生成快照(.rdb)文件保存到硬盘的过程,有手动触发和自动触发。
手动触发有save和bgsave两命令
该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。具体流程如下:
大家都不爱讲这个,我就贴个图吧。
执行完成时候如果存在老的RDB文件,就把新的替代掉旧的。我们的客户端可能都是几万或者是几十万,这种方式显然不可取。
在执行redis-cli shutdown关闭redis服务时,如果没有开启AOF持久化,自动执行save。(多谢大佬“花李胡哨”指正)
Redis主进程fork一个子进程来创建临时RDB存储文件,创建文件完成后对这个临时文件rename替换原先的RDB文件。RDB文件是一个单文件很适合数据的容灾备份与恢复,通过RDB文件恢复数据库耗时较短,通常1G的快照文件载入内存只需20s左右。
自动触发是由我们的配置文件来完成的。
save 900 1 save 300 10 save 60 10000 dbfilename "dump.rdb"
前三行都是对触发RDB的一个条件, 如第一行表示每900秒钟有一条数据被修改则触发RDB,依次类推;只要一条满足就会进行RDB持久化;
第四行dbfilename指定了把内存里的数据库写入本地文件的名称,该文件是进行压缩后的二进制文件;
自动触发bgsave。
命令:config set dir /usr/local //设置rdb文件保存路径
备份:bgsave //将dump.rdb保存到usr/local下
恢复:将dump.rdb放到redis安装目录与redis.conf同级目录,重启redis即可
该说的前面都说了,这里再加两点:
RDB是Redis数据的一个非常紧凑的单文件时间点表示。RDB文件非常适合备份。例如,你可能希望在最近24小时内每小时存档一次RDB文件,并在30天内每天保存一个RDB快照。这允许你在发生灾难时轻松恢复数据集的不同版本。
RDB非常适合灾难恢复,它是一个可以传输到远程数据中心或AmazonS3(可能是加密的)的压缩文件。
与AOF相比,RDB允许使用大数据集更快地重新启动。
如果你需要在Redis停止工作的情况下(例如在断电之后),将数据丢失的可能性降到最低,那么RDB是不好的。你可以配置不同的保存点让RDB至少可以保存5分钟的数据。因此,如果Redis由于任何原因没有正确关闭而停止工作,你应该做好好丢失最近几分钟的数据的心理准备。
RDB经常需要fork()才能使用子进程在磁盘上持久化。如果数据集很大,fork()可能很耗时,如果数据集非常大,CPU性能不好,可能会导致Redis停止为客户机服务几毫秒甚至一秒钟。
删除原有rdb文件,修改conf文件
客户端操作数据
服务器又生成一个rdb文件,并追加日志
服务器将rdb文件备份后删除
关闭客户端
重启服务器(忘了截)
再启动客户端,查询数据,发现并没有数据
以原备份rdb文件重启服务器
重启客户端,查询数据,数据依旧完好
针对RDB不适合实时持久化,redis提供了AOF持久化方式来解决
开启方式就是在redis.conf设置:appendonly yes (默认不开启,为no)
默认文件名:appendfilename “appendonly.aof”
当开启AOF后,服务端每执行一次写操作就会把该条命令追加到一个单独的AOF缓冲区的末尾,然后把AOF缓冲区的内容写入AOF文件里,由于磁盘缓冲区的存在写入AOF文件之后,并不代表数据已经落盘了,而何时进行文件同步则是根据配置的appendfsync来进行配置:appendfsync有三个选项:always、everysec和no:
服务器在每执行一个事件就把AOF缓冲区的内容强制性的写入硬盘上的AOF文件里,保证了数据持久化的完整性,效率是最慢的但最安全的;
服务端每隔一秒才会进行一次文件同步把内存缓冲区里的AOF缓存数据真正写入AOF文件里,兼顾了效率和完整性,极端情况服务器宕机只会丢失一秒内对Redis数据库的写操作;
表示默认系统的缓存区写入磁盘的机制,不做程序强制,数据安全性和完整性差一些。
设置appendonly yes;
将appendonly.aof放到dir参数指定的目录;
启动Redis,Redis会自动加载appendonly.aof文件。
AOF是通过保存Redis写操作的命令来实现持久化,使用AOF来持久化,Redis数据的安全性将大幅提高,异常宕机情况下最多丢失1s的数据。AOF文件记录了redis的写操作,格式清晰,易于理解和修改,利于数据的重建。
AOF日志是一个只附加的日志,因此如果断电,就不会出现查找或损坏问题。即使日志由于某种原因(磁盘已满或其他原因)以半写的命令结束,redis check aof工具也可以轻松地修复它。
当AOF太大时,Redis能够在后台自动重写AOF。重写是完全安全的,因为当Redis继续附加到旧文件时,一个全新的文件会生成,只需创建当前数据集所需的最少操作集,一旦第二个文件就绪,Redis就会切换这两个文件并开始附加到新文件中。
AOF以易于理解和解析的格式包含所有操作的日志。你甚至可以轻松导出AOF文件。
AOF文件通常比相同数据集的等效RDB文件大。
根据具体的fsync策略,AOF可能比RDB慢。
AOF比RDB文件更大,并且在存储命令的过程中增长更快,为了压缩AOF的持久化文件,Redis提供了重写机制以此来实现控制AOF文件的增长。AOF重写实现的理论基础是这样的:
执行set hello world 50次 最后执行一次 set hello china 最终对于AOF文件而言前面50次都是无意义的,AOF重写就是将key只保存最后的状态。
子进程在进行 AOF 重写期间, 主进程还需要继续处理命令, 而新的命令可能对现有的数据进行修改, 会出现数据库的数据和重写后的 AOF 文件中的数据不一致。因此Redis 增加了一个 AOF 重写缓存, 这个缓存在 fork 出子进程之后开始启用, Redis 主进程在接到新的写命令之后, 除了会将这个写命令的协议内容追加到现有的 AOF 文件之外, 还会追加到这个缓存中。
当子进程完成 AOF 重写之后向父进程发送一个完成信号, 父进程在接到完成信号之后会调用信号处理函数,完成以下工作:
将 AOF 重写缓存中的内容全部写入到新 AOF 文件中对新的 AOF 文件进行改名,覆盖原有的 AOF 文件
整个 AOF 后台重写过程中只有最后写入缓存和改名操作会造成主进程阻塞, 在其他时候AOF 后台重写都不会对主进程造成阻塞, 将 AOF 重写对性能造成的影响降到了最低。
AOF 重写可以由用户通过调用 BGREWRITEAOF 手动触发。服务器在 AOF 功能开启的情况下,会维持以下三个变量:
当前 AOF 文件大小 最后一次 重写之后, AOF 文件大小的变量 AOF文件大小增长百分比
每次当 serverCron 函数执行时, 它都会检查以下条件是否全部满足, 如果是的话, 就会触发自动的 AOF 重写:
没有 BGSAVE 命令在进行 防止于RDB的冲突 没有 BGREWRITEAOF 在进行 防止和手动AOF冲突当前 AOF 文件大小至少大于设定值 基本要求 太小没意义 当前 AOF 文件大小和最后一次 AOF 重写后的大小之间的比率大于等于指定的增长百分比
Redis恢复数据时会先检查AOF文件是否存在,如果不存在就尝试加载RDB文件。
在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不同情况,会有各种各样的持久化策略。如完全不使用任何持久化、使用RDB或AOF的一种,或同时开启RDB和AOF持久化等。
PS:持久化的选择必须与Redis的主从策略一起考虑,因为主从复制与持久化同样具有数据备份的功能,而且主机master和从机slave可以独立的选择持久化方案。