redis优化系列(十二)redis持久化之RDB和AOF

Redis持久化概述

持久化的功能介绍:Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。 当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。Redis持久化分为RDB持久化和AOF持久化,前者(RDB)将当前数据保存到硬盘,后者(AOF)则是将每次执行的写命令保存到硬盘。


一、RDB

RDB是一种快照存储持久化方式,具体就是将Redis某一时刻的内存数据保存到硬盘的文件当中,默认保存的文件名为dump.rdb,而在Redis服务器启动时,会重新加载dump.rdb文件的数据到内存当中恢复数据。触发 RDB 持久化过程分为手动触发和自动触发。

1.2、触发机制

手动触发分别对应 save 和 bgsave 命令:

①、save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用。

②、bgsave 命令:Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。


显然 bgsave 命令是针对 save 阻塞问题做的优化。因此 Redis 内部所有的涉及 RDB 的操作都采用 bgsave 的方式。


除了执行命令手动触发之外,Redis 内部还存在自动触发 RDB 的持久化机制,例如以下场景:

①、使用 save 相关配置,如“save m n”。表示 m 秒内数据集存在 n 次修改时,自动触发 bgsave。

②、如果从节点执行全量复制操作,主节点自动执行 bgsave 生成 RDB 文件并发送给从节点

③、执行 debug reload 命令重新加载 Redis 时,也会自动触发 save 操作。

④、默认情况下执行 shutdown 命令时,如果没有开启 AOF 持久化功能则自动执行 bgsave。

1.3、工作流程说明

bgsave 是主流的触发 RDB 持久化方式,根据下图了解它的运作流程:

r1.png

流程解析说明:

①、执行 bgsave 命令,Redis 父进程判断当前是否存在正在执行的子进程,如 RDB/AOF 子进程,如果存在 bgsave 命令直接返回。

②、父进程执行 fork 操作创建子进程,fork 操作过程中父进程会阻塞,通过 info stats 命令查看 latest_fork_usec 选项,可以获取最近一个 fork 操作的耗时,单位为微秒。

③、父进程 fork 完成后,bgsave 命令返回“Background saving started”信息并不再阻塞父进程,可以继续响应其他命令。

④、子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行 lastsave 命令可以获取最后一次生成RDB 的时间,对应 info 统计的 rdb_last_save_time 选项。

⑤、进程发送信号给父进程表示完成,父进程更新统计信息,具体见 info Persistence 下的 rdb_* 相关选项。


1.4、服务器配置自动触发

除了通过客户端发送命令外,还有一种方式,就是在Redis配置文件中的save指定到达触发RDB持久化的条件,比如【多少秒内至少达到多少写操作】就开启RDB数据同步。

例如我们可以在配置文件redis.conf指定如下的选项:

# 900s内至少达到一条写命令
save 900 1

# 300s内至少达至10条写命令
save 300 10

# 60s内至少达到10000条写命令
save 60 10000

这种通过服务器配置文件触发RDB的方式,与bgsave命令类似,达到触发条件时,会forks一个子进程进行数据同步, 不过最好不要通过这方式来触发RDB持久化,因为设置触发的时间太短,则容易频繁写入rdb文件,影响服务器性能, 时间设置太长则会造成数据丢失。

1.5、RDB 文件的处理

①、保存:

RDB 文件保存在 dir 配置指定的目录下,文件名通过 dbfilename 配置指定。可以通过执行 config set dir{newDir}和 config set dbfilename{newFileName}运行期动态执行,当下次运行时 RDB 文件会保存到新目录。

当遇到坏盘或磁盘写满等情况时,可以通过 config set dir{newDir}在线修改文件路径到可用的磁盘路径,之后执行 bgsave 进行磁盘切换,同样适用于 AOF 持久化文件。


②、压缩:

Redis 默认采用 LZF 算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数 config set rdbcompression{yes|no}动态修改。


虽然压缩 RDB 会消耗 CPU,但可大幅降低文件的体积,方便保存到硬盘或通过网络发送给从节点,因此线上建议开启。

1.6、RDB方式的优点

①、RDB 是一个非常紧凑的文件,它保存了 Redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份: 比如说,你可以在最近的24小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。


②、RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。


③、RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

1.7、RDB方式的缺点

①、RDB 方式数据没办法做到实时持久化/秒级持久化。如果服务器宕机的话,采用RDB的方式会造成某个时段内数据的丢失,比如我们设置10分钟同步一次或5分钟达到1000次写入就同步一次,那么如果还没达到触发条件服务器就死机了,那么这个时间段的数据会丢失。


②、使用bgsave命令在forks子进程时,如果数据量太大,forks的过程也会发生阻塞,另外,forks子进程会耗费内存。针对 RDB 不适合实时持久化的问题,Redis 提供了 AOF 持久化方式来解决。

二、AOF

AOF(append only file)持久化:与RDB存储某个时刻的快照不同,AOF持久化方式会记录客户端对服务器的每一次写操作命令到日志当中,并将这些写操作以Redis协议追加保存到以后缀为aof文件末尾。

2.1、使用AOF

开启 AOF 功能需要在配置文件中配置:appendonly yes,默认不开启。AOF 文件名通过 appendfilename 配置设置,默认文件名是 appendonly.aof。保存路径同RDB 持久化方式一致,通过 dir 配置指定。

2.2、配置说明

appendonly yes  #启用aof持久化方式。


appendfsync always #每次收到写命令就立即强制写入磁盘,最慢的大概只有几百的TPS,但是保证完全的持久化,不推荐使用 。


appendfsync everysec #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中。

appendfsync no #推荐 完全依赖os,性能最好,持久化没保证,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。对大多数Linux操作系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上。

2.3、工作流程说明

r1.png

流程解析说明如下:

①、所有的写入命令会追加到 aof_buf(缓冲区)中。

②、AOF 缓冲区根据对应的策略向硬盘做同步操作。

③、随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。

④、当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。

2.3.1、重写机制说明

AOF将客户端的每一个写操作都追加到aof文件末尾,随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引入 AOF 重写机制压缩文件体积。


AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新 AOF 文件的过程。


比如:

多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush list c 可以转化为:lpush list a b c


AOF 重写降低了文件占用空间,除此之外,另一个目的是:更小的 AOF 文件可以更快地被 Redis 加载。

2.4、触发机制

AOF 重写过程可以手动触发和自动触发。


手动触发:直接调用 bgrewriteaof 命令。


自动触发:根据 auto-aof-rewrite-min-size和auto-aof-rewrite-percentage 参数确定自动触发时机。

    auto-aof-rewrite-min-size:表示运行 AOF 重写时文件最小体积,默认:64MB。

    auto-aof-rewrite-percentage:代表当前 AOF 文件空间(aof_current_size)和上一次重写后 AOF 文件空间(aof_base_size)的比值。


示例:

auto-aof-rewrite-percentage:100

auto-aof-rewrite-min-size:64MB

默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。


当触发 AOF 重写时,内部做了哪些事呢?接下来介绍下它的运行流程,且看下图

r1.png

1)执行 AOF 重写请求。 如果当前进程正在执行 AOF 重写,请求不执行并返回如下响应: ERR Background append only file rewriting already in progress

2)父进程执行 fork 创建子进程,开销等同于 bgsave 过程。

3.1)主进程 fork 操作完成后,继续响应其他命令。所有修改命令依然写入 AOF 缓冲区并根据 appendfsync 策略同步到硬盘,保证原有 AOF 机制正确性。

3.2)由于 fork 操作运用写时复制技术,子进程只能共享 fork 操作时的内存数据。由于父进程依然响应命令,Redis 使用“AOF 重写缓冲区”保存这部分新数据,防止新 AOF 文件生成期间丢失这部分数据。


4)子进程根据内存快照,按照命令合并规则写入到新的 AOF 文件。每次批量写入硬盘数据量由配置 aof-rewrite-incremental-fsync 控制,默认为 32MB,防止单次刷盘数据过多造成硬盘阻塞。

4.1)新 AOF 文件写入完成后,子进程发送信号给父进程,父进程更新统计信息,具体见 info persistence 下的 aof_*相关统计。

4.2)父进程把 AOF 重写缓冲区的数据写入到新的 AOF 文件。

4.3)使用新 AOF 文件替换老文件,完成 AOF 重写。

2.5、AOF注意事项

1、AOF文件损坏

在写入aof日志文件时,如果Redis服务器宕机,则aof日志文件文件会出格式错误,在重启Redis服务器时,Redis服务器会拒绝载入这个aof文件,可以通过命令修复aof并恢复数据:redis-check-aof -fix file.aof

2.6、AOF的优点

①、AOF可以设置 完全不同步、每秒同步、每次操作同,默认是每秒同步。因为AOF是操作指令的追加,所以可以频繁的大量的同步。

②、AOF文件是一个值追加日志的文件,即使服务宕机为写入完整的命令,也可以通过redis-check-aof工具修复这些问题。

③、如果AOF文件过大,Redis会在后台自动地重写AOF文件。重写后会使AOF文件压缩到最小所需的指令集。

④、AOF文件是有序保存数据库的所有写入操作,易读,易分析。即使如果不小心误操作数据库,也很容易找出错误指令,恢复到某个数据节点。例如不小心FLUSHALL,可以非常容易恢复到执行命令之前。

2.7、AOF的缺点

①、相同数据量下,AOF的文件通常体积会比RDB大。因为AOF是存指令的,而RDB是所有指令的结果快照。但AOF在日志重写后会压缩一些空间。

②、在大量写入和载入的时候,AOF的效率会比RDB低。因为大量写入,AOF会执行更多的保存命令,载入的时候也需要大量的重执行命令来得到最后的结果。

RDB对此更有优势。

2.8、重启加载的选择

AOF 和 RDB 文件都可以用于服务器重启时的数据恢复。

r1.png

2.9、AOF常用配置总结

appendonly no:是否开启AOF 

appendfilename "appendonly.aof":AOF文件名

dir ./:RDB文件和AOF文件所在目录

appendfsync everysec:fsync持久化策略

no-appendfsync-on-rewrite no:AOF重写期间是否禁止fsync;如果开启该选项,可以减轻文件重写时CPU和硬盘的负载(尤其是硬盘),但是可能会丢失AOF重写期间的数据;需要在负载和安全性之间进行平衡


auto-aof-rewrite-percentage 100:文件重写触发条件之一

auto-aof-rewrite-min-size 64mb:文件重写触发提交之一

aof-load-truncated yes:如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件

三、持久化之间的选择

在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不同情况,会有各种各样的持久化策略;如完全不使用任何持久化、使用RDB或AOF的一种,或同时开启RDB和AOF持久化等。此外,持久化的选择必须与Redis的主从策略一起考虑,因为主从复制与持久化同样具有数据备份的功能,而且主机master和从机slave可以独立的选择持久化方案。


面分场景来讨论持久化策略的选择,下面的讨论也只是作为参考,实际方案可能更复杂更具多样性。

1)如果Redis中的数据完全丢弃也没有关系(如Redis完全用作DB层数据的cache),那么无论是单机,还是主从架构,都可以不进行任何持久化。

2)在单机环境下(对于个人开发者,这种情况可能比较常见),如果可以接受十几分钟或更多的数据丢失,选择RDB对Redis的性能更加有利;如果只能接受秒级别的数据丢失,应该选择AOF。


3)但在多数情况下,我们都会配置主从环境,slave的存在既可以实现数据的热备,也可以进行读写分离分担Redis读请求,以及在master宕掉后继续提供服务。

在这种情况下的做法是:

master:完全关闭持久化(包括RDB和AOF),这样可以让master的性能达到最好。

slave:关闭RDB,开启AOF(如果对数据安全要求不高,开启RDB关闭AOF也可以),并定时对持久化文件进行备份(如备份到其他文件夹,并标记好备份的时间)。然后关闭AOF的自动重写,然后添加定时任务,在每天Redis闲时(如凌晨12点)调用bgrewriteaof。


4)异地灾备:上述讨论的几种持久化策略,针对的都是一般的系统故障,如进程异常退出、宕机、断电等,这些故障不会损坏硬盘。但是对于一些可能导致硬盘损坏的灾难情况,如火灾地震,就需要进行异地灾备。


例如对于单机的情形,可以定时将RDB文件或重写后的AOF文件,通过scp拷贝到远程机器,如阿里云。对于主从的情形,可以定时在master上执行bgsave,然后将RDB文件拷贝到远程机器。或者在slave上执行bgrewriteaof重写AOF文件后,将AOF文件拷贝到远程机器上。


一般来说,由于RDB文件文件小、恢复快,因此灾难恢复常用RDB文件;异地备份的频率根据数据安全性的需要及其它条件来确定,但最好不要低于一天一次。


注意:

①、RDB虽然可以通过bgsave指令后台保存快照,但fork()子进程是有开销的,在内存数据集较大的情况下会占用很长的cpu时间,fork新进程时这个复制是需要时间的,在服务器结点上测试,35G的数据bgsave瞬间会阻塞200ms以上,一般建议Redis使用内存不超过20g。

②、I/O消耗的问题:线上是在Slave节点开启rdb持久化,磁盘性能一般,1.2g的rdb文件持久化一分钟一次,一次大概耗时30s左右,所以rdb的频率也不能太频繁,需要根据情况做好配置。

③、AOF是追加写命令到aof文件的方式,优点是可以基本做到数据无损,缺点是文件增长较快,需要间歇性bgrewrite,bgrewrite也是一个既耗cpu又耗磁盘IO的操作,单cpu利用率最高可达100%,一般建议找几个空闲时段设置脚本来做bgrewrite。

四、持久化配置方案

4.1、企业级的持久化的配置策略

①、save 60 10000:如果你希望尽可能确保说,RDB最多丢1分钟的数据,那么尽量就是每隔1分钟都生成一个快照,低峰期,数据量很少,也没必要10000->生成RDB,1000->RDB,这个根据你自己的应用和业务的数据量,你自己去决定。


②、AOF一定要打开,fsync,everysec

auto-aof-rewrite-percentage 100: 就是当前AOF大小膨胀到超过上次100%,上次的两倍

auto-aof-rewrite-min-size 64mb:根据你的数据量来定,16mb,32mb

4.2、数据备份方案

RDB非常适合做冷备,每次生成之后,就不会再有修改了。

数据备份方案

(1)写crontab定时调度脚本去做数据备份

(2)每小时都copy一份rdb的备份,到一个目录中去,仅仅保留最近48小时的备份

(3)每天都保留一份当日的rdb的备份,到一个目录中去,仅仅保留最近1个月的备份

(4)每次copy备份的时候,都把太旧的备份给删了

(5)每天晚上将当前服务器上所有的数据备份,发送一份到远程的云服务上去【crontab】

五、常见问题答疑

1、为什么开启了主从复制,可以实现数据的热备份,还需要设置持久化呢?

因为在一些特殊情况下,主从复制仍然不足以保证数据的安全,例如:

①、master和slave进程同时停止:考虑这样一种场景,如果master和slave在同一个机房,则一次停电事故就可能导致master和slave机器同时关机,Redis进程停止。如果没有持久化,则面临的是数据的完全丢失。

②、master误重启:考虑这样一种场景,master服务因为故障宕掉了,如果系统中有自动拉起机制(即检测到服务停止后重启该服务)将master自动重启,由于没有持久化文件,那么master重启后数据是空的,slave同步数据也变成了空的。

③、如果master和slave都没有持久化,同样会面临数据的完全丢失。需要注意的是,即便是使用了哨兵进行自动的主从切换,也有可能在哨兵轮询到master之前,便被自动拉起机制重启了。因此,应尽量避免“自动拉起机制”和“不做持久化”同时出现。


如果需要最大限度需要数据无损:

建议master开启aof,slave开启aof,开启aof需要cpu和磁盘性能保障。开启aof建议fsync同步刷盘使用everysec,自定义脚本在应用空闲时定时做bgrewrite。



醉过才知酒浓,爱过才知情重    -->胡适【梦与诗】


a1.png



声明:禁止任何非法用途使用,凡因违规使用而引起的任何法律纠纷,本站概不负责。

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

精彩评论

全部回复12人评论7,777人参与