redis持久化(RDB、AOF、混合持久化)

1. RDB快照(snapshot)

在默认情况下, Redis 将内存数据库快照保存在名字为 dump.rdb的二进制文件中。


你可以对 Redis 进行设置, 让它在“N 秒内数据集至少有 M 个改动”这一条件被满足时,

自动保存一次数据集。

比如说, 以下设置会让 Redis 在满足“60 秒内有至少有 1000 个键被改动”这一条件时,

自动保存一次数据集:

save 60 1000

优点:

RDB 是一个非常紧凑(compact)的文件,体积小,因此在传输速度上比较快,因此适合灾难恢复。

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

缺点:

RDB是一个快照过程,无法完整的保存所有数据,尤其在数据量比较大时候,一旦出现故障丢失的数据将更多。

RDB文件是特定的格式,阅读性差,由于格式固定,可能存在不兼容情况。

~~~

bgsave

~~~

bgsave执行原理:

针对save命令进行优化,Redis中所有涉及RDB操作都采用bgsava方式 

优势

1.采用子线程创建RDB文件(),不会对redis服务器性能造成大的影响( 性能最大化);

2.快照生成的RDB文件是一种压缩的二进制文件,可以方便的在网络中传输和保存。通过RDB文件可以方便的将redis数据恢复到某一历史时刻,可以提高数据安全性,避免宕机等意外对数据的影响。

3.适合大规模的数据恢复, RDB的启动恢复效率高。

4.如果业务对数据完整性和一致性要求不高,RDB是很好的选择。 


劣势

1.在redis文件在时间点A生成,之后产生了新数据,还未到达另一次生成RDB文件的条件,redis服务器崩溃了,那么在时间点A之后的数据会丢失掉,数据一致性不是完美的好,如果可以接受这部分丢失的数据,可以用生成RDB的方式;

2.快照持久化方法通过调用fork()方法创建子线程。当redis内存的数据量比较大时,创建子线程和生成RDB文件会占用大量的系统资源和处理时间,对 redis处理正常的客户端请求造成较大影响。

3.数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。

4.备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍哦),最后再将临时文件替换之前的备份文件。所以 Redis 的持久化和数据的恢复要选择在夜深人静的时候执行是比较合理的。

Q: 通过RDB文件恢复数据?

答: 将dump.rdb 文件拷贝到redis的安装目录的bin目录下,重启redis服务即可。在实际开发中,一般会考虑到物理机硬盘损坏情况,选择备份dump.rdb 。 作者:WeiyiGeek https://www.bilibili.com/read/cv13235983 出处:bilibili

RDB文件恢复数据流程 

 1、先备份一份 dump.rdb 为 dump_bak.rdb(模拟线上)

 2、flushall 清空数据(模拟数据丢失,需要注意 flushall 也会触发rbd持久化) 

3、将 dump_bak.rdb 替换为 dump.rdb 

4、重启redis服务,恢复数据 


2. AOF(append-only file)

快照功能并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化,将修改的每一条指令记录进文件



AOF文件生成机制

答: 生成过程包括三个步骤,即。

redis 打开AOF持久化功能之后,redis在执行完一个写命令后,把执行的命令首先追加到redis内部的aof_buf缓冲区膜末尾,此时缓冲区的记录还没有写到Appendonly.aof文件中。然后,缓冲区的写命令会被写入到 AOF 文件,这一过程是文件写入过程。对于操作系统来说,调用write函数并不会立刻将数据写入到硬盘,为了将数据真正写入硬盘,还需要调用fsync函数,调用fsync函数即是文件同步的过程,只有经过了文件的同步过程,写命令才真正的被保存到了AOF文件中。选项 Appendfsync 就是配置同步的频率的。 


你可以通过修改配置文件来打开 AOF 功能:

appendonly yes

从现在开始, 每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。

这样的话, 当 Redis 重新启动时, 程序就可以通过重新执行 AOF 文件中的命令来达到重建数据集的目的。

你可以配置 Redis 多久才将数据 fsync 到磁盘一次。

有三个选项:

appendfsync always。每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全。

appendfsync everysec。每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。

appendfsync no。从不 fsync :将数据交给操作系统来处理。更快,也更不安全的选择。

推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。

优点:

数据更完整,秒级数据丢失(取决于设置fsync策略)。、

兼容性较高,由于是基于redis通讯协议而形成的命令追加方式,无论何种版本的redis都兼容。

aof文件是明文的,可阅读性较好。

缺点:

数据文件体积较大,即使有重写机制,但是在相同的数据集情况下,AOF文件通常比RDB文件大。

相对RDB方式,AOF速度慢于RDB,并且在数据量大时候,恢复速度AOF速度也是慢于RDB。

由于频繁地将命令同步到文件中,AOF持久化对性能的影响相对RDB较大。

AOF文件重写

1、redis不断的将写命令保存到AOF文件中,导致AOF文件越来越大,当AOF文件体积过大时,数据恢复的时间也是非常长的,因此,redis提供了重写或者说压缩AOF文件的功能。

比如,AOF重写功能就是干这个事情的。重写时,可以调用BGREWRITEAOF命令重写AOF文件,与新建子线程bgsave命令的工作原理相似。也可以通过配置文件配置什么条件下对AOF文件重写。

2、重写的原理:Redis 会fork出一条新进程,读取内存中的数据,并重新写到一个临时文件中。并没有读取旧文件(太大了)。最后替换旧的aof文件

3、重写触发机制:当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发,这里的“一倍”和“64M” 可以通过配置文件修改

aof 文件记录的是每一条redis命令,有时候我们会对某一个key进行多次set,中间会产生很多条命令,但是结果只有一个。

优势

1.该机制可以带来更高的数据安全性,即数据持久化; 常规三种同步策略即每秒同步()、每修改同步()和不同步;

2.由于该机制对日志文件的写入操作采用的是Append模式,即使过程中出现宕机也不会破坏日志文件中已经存在的内容,如果数据不完整在Redis下次启动之前, 通过redis-check-aof解决数据一致性问题;

3.如果日志文件体积过大可以启动rewrite机制,即redis以Append模式不断的将修改数据写到老的磁盘文件中,同时创建新文件记录期间有哪些修改命令执行,此项极大的保证数据的安全性;

4.AOF文件可读性强,其包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作()

5.数据的完整性和一致性更高

劣势

1.AOF文件比RDB文件较大, 对于相同数量的数据集而言;

2.redis负载较高时,RDB文件比AOF文件具有更好的性能;

3.RDB使用快照的方式持久化整个redis数据,而aof只是追加写命令,因此从理论上来说,RDB比AOF方式更加健壮,另外,官方文档也指出,在某些情况下,AOF的确也存在一些bug,比如使用阻塞命令时,这些bug的场景RDB是不存在的。

4.因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢。

5.根据同步策略的不同,AOF在运行效率上往往会慢于RDB,总的来说每秒同步策略的效率还是比较高的 


set name 1

...

set name 12

set name 123

...

set name 1234

set name 12345

例如我们执行了上述命令,aof 文件会记录着每一条命令。在redis重启时,会逐条执行上述的命令。但是其实可以精简为set name 12345,其余的几条命令其实没有意义。AOF重写就是实现了这个功能。

相关配置:

auto-aof-rewrite-percentage 100  # 指当前aof文件比上次重写的增长比例大小,达到这个大小就进行 aof 重写

auto-aof-rewrite-min-size 64mb  # 最开始aof文件必须要达到这个文件时才触发,后面的每次重写就不会根据这个变量了

以上配置的意思是:

在 aof 文件小于64mb的时候不进行重写,当到达64mb的时候,就重写一次。重写后的 aof 文件可能是10mb。上面配置了auto-aof-rewrite-percentage 100,即 aof 文件到了20mb的时候,又开始重写一次。以此类推。

AOF 是在后台自动重写(redis会fork一个子进程来进行备份,保证主进程不会阻塞),也可以人为执行命令 bgrewriteaof 重写 AOF。

使用子进程来进行AOF重写时会遇到的问题

问题:

子进程在进行AOF重写期间,服务器进程还要继续处理命令请求,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的AOF文件中的数据不一致。

解决方案:

要知道redis是怎么处理这个问题的,需要先了解下AOF重写的具体实现:

AOF文件重写过程与RDB快照bgsave工作过程有点相似,都是通过fork子进程,由子进程完成相应的操作,同样的在fork子进程简短的时间内,redis是阻塞的。

(1)开始bgrewriteaof,判断当前有没有bgsave命令(RDB持久化)/bgrewriteaof在执行,倘若有,则这些命令执行完成以后在执行。

(2)主进程fork出子进程,在这一个短暂的时间内,redis是阻塞的。

(3)主进程fork完子进程继续接受客户端请求。此时,客户端的写请求不仅仅写入aof_buf缓冲区,还写入aof_rewrite_buf重写缓冲区。一方面是写入aof_buf缓冲区并根据appendfsync策略同步到磁盘,保证原有AOF文件完整和正确。另一方面写入aof_rewrite_buf重写缓冲区,保存fork之后的客户端的写请求,防止新AOF文件生成期间丢失这部分数据。

(4.1)子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。

(4.2)主进程把aof_rewrite_buf中的数据写入到新的AOF文件。

(5.)使用新的AOF文件覆盖旧的AOF文件,标志AOF重写完成。

手动执行重写


AOF写和重写流程:

Q: 如何触发AOF快照?

答: 根据配置文件触发,可以是每次执行触发,可以是每秒触发,可以不同步。

Q: 如何根据AOF文件恢复数据?

答: 正常情况下,将Appendonly.aof 文件拷贝到redis的安装目录的bin目录下,重启redis服务即可。但在实际开发中,可能因为某些原因导致  文件格式异常,从而导致数据还原失败,可以通过命令进行修复 。 

配置说明: 

~~~

cat > redis.conf <<'EOF'

# 持久化数据存储

dir "/data"

# 是否开启AOF默认为否

appendonly yes

# AOF文件名字及路径,若RDB路径已设置这里可不设置

appendfilename "appendonly.aof"

# AOF的3种模式,no(使用系统缓存处理,快)、always(记录全部操作,慢但比较安全)、everysec(每秒同步,折中方案,默认使用)

appendfsync everysec

# 重写期间是否同步数据,默认为no

no-appendfsync-on-rewrite no

# 配置重写触发机制: 确保AOF日志文件不会过大,保持跟redis内存数据量一致。

# 配置说明:当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发(根据实际环境进行配置)

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 256mb

# AOF重写策略是否启用,默认为yes

aof-rewrite-incremental-fsync yes

# 加载AOF时如果报错则会继续但写入log,如果为no则不会继续

aof-load-truncated yes

# Redis5.0有的功能AOF重写及恢复可以使用RDB文件及AOF文件,速度更快,默认yes

aof-use-rdb-preamble yes

EOF

~~~

Q: 如何通过AOF文件恢复数据流程? 

1、执行flushall,模拟数据丢失

2、重启 redis 服务,恢复数据

3、修改 appendonly.aof,模拟文件异常

4、重启 Redis 服务失败,这同时也说明了RDB和AOF可以同时存在,且优先加载AOF文件。

5、使用 redis-check-aof 校验 appendonly.aof 文件。

#  针对Redis aof 持久化文件进行完整性检测并进行修复

/usr/local/redis/bin/redis-check-aof --fix appendonly.aof

  # The AOF appears to start with an RDB preamble.

  # Checking the RDB preamble to start:

  # [offset 0] Checking RDB file appendonly.aof

  # [offset 27] AUX FIELD redis-ver = '5.0.10'

  # [offset 41] AUX FIELD redis-bits = '64'

  # [offset 53] AUX FIELD ctime = '1631088747'

  # [offset 68] AUX FIELD used-mem = '31554944'

  # [offset 84] AUX FIELD aof-preamble = '1'

  # [offset 86] Selecting DB ID 0

  # [offset 13350761] Checksum OK

  # [offset 13350761] \o/ RDB looks OK! \o/

  # [info] 157070 keys read

  # [info] 0 expires

  # [info] 0 already expired

  # RDB preamble is OK, proceeding with AOF tail...

  # 0x        27b66b0: Expected prefix '*', got: 'R'

  # AOF analyzed: size=116993914, ok_up_to=41641648, ok_up_to_line=1816854, diff=75352266

  # AOF is not valid. Use the option to try fixing it.

6、重启Redis 服务后正常。

# 利用源实例生成的aof文件数据进行恢复到其它主机中。

redis-cli -h 17.20.0.2 -a password --pipe < applendonly.aof

注意:当你使用 flushall 清空数据的时候,重启redis服务发现数据没恢复,是因为 FLUSHALL 命令也被写入AOF文件中,会导致数据恢复失败,所只需要删除aof文件中的flushall就行了。

在数据库恢复时把 aof(Append only file) 从中对redis数据库操作的命令,增删改操作的命令,执行了一遍即可。

实际案例:

描述: 用于异步执行一个  文件重写操作, 重写会创建一个当前 AOF 文件的体积优化版本,因为AOF为记录每次的操作会导致实际记录冗杂、使得文件过大,所以需要做重写操作。

重写方式分为以下两种:

# (1) AOF自动重写:按配置文件条件自动触发重写

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 256mb

# (2) AOF手动重写:使用 redis-cli 连接到 server 端执行 bgrewriteaof 进行手动重写。

# 注意:从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。

127.0.0.1:6379> BGREWRITEAOF

# 即使 Bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 Bgrewriteaof 成功之前不会被修改。

Background append only file rewriting started 

合并两个不同实例的数据 

描述: 我们可以利用如下方式进行集群多个主节点持久化数据的合并。

(1) AOF 备份合并: 我们说过它实际上是一些列Redis的命令文本。

例如,假设有两台 Redis(6379, 6479),它们的AOF文件名分别为(6379.aof, 6479.aof),现在要将6379的数据合并到 6479.aof 

# 首先

cp 6379.aof 6379.aof.bak, cp 6479.aof 6479.aof.bak

# 合并

cat 6379.aof 6479.aof > new.aof

# 检查&修复

/usr/local/redis/bin/redis-check-aof --fix appendonly.aof

(2) RDB 备份合并: 注意以下方法可能由于服务端版本不同而有些许差异。

RDB格式如下:头5个字节是字符REDIS,之后4个字节代表版本号,阿里的版本分别是 00 00 00 06,之后2个字节 FE 00,FE是标识 00是数据库,还好我们只有一个库, 最后的结尾9个字节 , FF 加上8个字节的CRC64校验码(实在没空弄,后来偷了一个懒)

# 1.线上服务使用的阿里云的集群版本redis服务,数据量1千万,rdb文件4GB,8个rdb文件,每个500MB。

#文件1 大小566346503,截取尾部的9个字节

dd bs=1 if=src_1.rdb of=1.rdb count=566346494

#文件2 大小570214520,跳过头部的11个字节,再截取尾部的9个字节

dd bs=1 if=src_2.rdb of=2.rdb skip=11 count=570214500

...

#文件8 大小569253061,跳过头部的11个字节,再截取尾部的8个字节,保留FF。

dd bs=1 if=src_8.rdb of=8.rdb skip=11 count=569253042

# 2.合并文件(得到备份文件dump.rdb)

cat 1.rdb > dump.rdb

cat 2.rdb >> dump.rdb

...

cat 8.rdb >> dump.rdb

# 3.检查备份文件(应该会提示没有crc校验)

redis-check-rdb dump.rdb

# 4.修改配置文件,因为数据库备份文件里面不包含crc64的校验码,配置文件中关闭选项。

rdbchecksum no 

Tips : 数据恢复到此结束,此方法只适合用于临时恢复和导出数据,数据完整性不敢保证。

参考地址: https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format

其它工具:

https://github.com/leonchen83/redis-rdb-cli/ | 一个可以解析, 过滤, 分割, 合并 rdb 离线内存分析的工具. 也可以在两个redis之前同步数据并允许用户自定义同步服务来把redis数据同步到其他地方. 


3.混合持久化(redis4.0之后才支持)

重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。

如果使用 AOF 日志重放,性能则相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动的时候需要花费很长的时间。

Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。

混合持久化同样也是通过bgrewriteaof完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将aof_rewrite_buf重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据,如下图:

在redis重启的时候,加载 aof 文件进行恢复数据:先加载 rdb 内容再加载剩余的 aof。

混合持久化配置:

aof-use-rdb-preamble yes  # yes:开启,no:关闭

RDB和AOF,应该用哪一个?

如果你可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。

有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。如果只用AOF持久化,数据量很大时,在redis启动的时候需要花费大量的时间。

如果你非常关心你的数据,建议使用 redis 4.0 以后的混合持久化特性。


混合模式配置项

save " "

dbfilename "dump.rdb"

appendonly "yes"

appendfilename "appendonly.aof"

AOF重写

aof文件里可能有太多“琐碎”指令,所以aof会定期根据内存的最新数据重新生成aof文件

有两个配置可以控制aof自动重写的频率:

auto-aof-rewrite-min-size  64mb

#aof文件至少要达到64m才会触发制动重写,文件太小恢复速度本来就很快,重写的意义不大

auto-aof-rewrite-percentage  100

#aof文件上一次重写后文件大小增长了100%则再次触发重写

appendfsync   "everysec"

aof-use-rdb-preamble "yes"


参考:https://www.bilibili.com/read/cv13235983 

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容