Redis的持久化方案,RDB和AOF详解

目录

一.Redis持久化方案(RDB和AOF)

1.1 RDB(Redis DataBase)

1.1.1 原理介绍

1.1.2 触发快照的机制

1.1.3 RDB快照文件压缩方式

1.1.4 关于RDB的配置

1.2 AOF(Append Only File)

1.2.1 原理介绍

2.1.2 AOF同步策略

2.1.3 AOF重写策略

2.1.4 AOF重写条件

 


Redis是内存型数据库。为实现可靠性,Redis也会将内存的数据持久化

一.Redis持久化方案(RDB和AOF)

1.1 RDB(Redis DataBase)

1.1.1 原理介绍

RDB通过将Redis当前的所有数据生成一个快照(Snapshoting),存储在硬盘中。快照文件默认为dump.rdb

当Redis重启后,Redis会去读取这个快照,并恢复数据。

好比一个黑板(内存),会有很多人去写它,某一瞬间,我把整块黑板拍下来(持久化)。

当黑板被擦掉,我可以迅速通过照片,恢复黑板上的数据。

1.1.2 触发快照的机制

    上面那块黑板我不能太频繁拍照,必须有对应的触发机制

    redis中有如下的5种触发机制:

  • 通过配置文件配置,在一段时间间隔内,执行了相应的修改,自动触发快照。转 1.1.4 关于RDB的配置
  • 执行save命令,手动触发快照。save命令执行后,redis执行快照功能,并阻塞其他操作。线上环境禁止使用,会阻塞redis的正常使用。
  • 执行bgsave命令,手动触发快照。异步执行快照功能,极短的阻塞其他操作。通过fork子进程进行快照的持久化工作。
  • 执行flushall命令,自动触发快照。清空数据库所有数据。
  • 执行shutdown命令,自动触发快照。关闭数据库。

1.1.3 RDB快照文件压缩方式

    采用LZF的压缩方式,LZF压缩:

1.1.4 关于RDB的配置

  • RDB持久化可设置触发机制:通过redis.conf中的save设置,默认如下:
    save  
    # save ""
    save 900 1
    save 300 10
    save 60 10000
    900秒内有1个修改。300秒内有10个修改。60秒秒内有10000个修改。

什么意思呢?

就是有个比方说有三个计时器,当数到60秒的时候,如果Redis修改了1万次,那么拍一张皂片。并且60秒这个计时器置零重新计时,有一个计时器计时到300秒时,如果有10个修改,那么拍皂。900秒同理。

简单的说就是每seconds时间间隔内如果修改了changes次redis,那么拍一张照。

如果只想使用缓存并停用持久化功能,那么我们注释所有save行,设置为 save ""即可。

  • RDB快照文件可设置快照文件存储路径:通过redis.conf中的dir设置,默认为执行“启动redis服务“”命令时的路径。
    dir ./
  • RDB快照文件可设置名字:通过redis.conf中的dbfilename设置,默认为dump.rdb。
    dbfilename dump.rdb
  • RDB快照可设置是否压缩:通过redis.conf中的rdbcompression设置,默认为yes(压缩关闭后,文件较大,建议开启)。
    rdbcompression yes
  • RDB快照存储后可以设置是否校验数据CRC64算法:通过redis.conf中的rdbchecksum设置,默认为yes,会增加约10%的性能消耗。

    rdbchecksum yes
  • RDB可以设置当持久化(拍照)失败后,是否停止用户写功能:通过redis.conf中的rdbchecksum设置,它能让用户更快的发现Redis持久化失败。默认为yes。
    stop-writes-on-bgsave-error yes

1.2 AOF(Append Only File)

1.2.1 原理介绍

AOF通过将redis每次执行的修改命令记录到单独的日志文件(appendonly.aof),Redis回复数据的时候通过再次执行一遍日志中的命令来恢复数据。

好比这个黑板,我记录每次在上面写数据的操作,当需要再次恢复数据,我参考之前记录的操作再操作一遍就是了

可以查看下图运行的图片,以及aof文件中redis写入的日志信息。

Redis的持久化方案,RDB和AOF详解_第1张图片

我们可以看见如果对redis的操作分为 读-写操作,这里aof会记录对redis的写操作,这里的写操作并非只说是往里面写入数据的操作(set)。删除,修改也算是写操作。此写非彼写。很多博客里没有指明,容易出现误解。这里特别指明一下。并且这里注意一下读操作。get 以及其他数据格式的读都是不做记录的。

2.1.2 AOF同步策略

同步策略指将对redis的写命令同步到日志中。也就是持久化到硬盘中。

在redis.conf中配置(windows下的配置文件为redis.windows.conf

  • appendfsync always   同步持久化, 每次发生数据变更就会被立即记录到磁盘  性能较差但不会丢失数据。
  • appendfsync everysec    异步操作,每秒往硬盘记录一次操作,如果一秒内宕机,有数据丢失,丢失一秒数据。
  • appendfsync no   同步交由操作系统决定,当到达一定时限,或一定限度的内存被写满,操作系统将会同步数据。

补充知识:

redis的操作分两步,先写操作,然后将内存中的数据同步到磁盘中。

Redis会调用操作系统中的write函数和fsync函数,分别对应redis操作中的写操作和同步操作。

在现代操作系统中,操作系统通常将数据缓存在内存缓冲区中,当缓冲区写满或超过未同步的时限后,系统才把缓冲区写入硬盘。当然未同步的数据如果系统宕掉,这些数据就丢失了。因此操作系统提供fsync函数让应用程序立即同步数据到硬盘。

  • 所以在配置 appendfsync 为 always 后如果有大量的redis写操作,每次写操作都会同步数据,磁盘IO将会跟不上。这里最好不要设置为always。
  • 所以在配置 appendfsync 为 no 后,这样redis将不接管同步操作,同步操作由操作系统决定,一般为30秒。当文件同步时间不可控后,系统宕机后,丢失的数据量也将不可控。
  • 所以这里有个折中方案。就是everysec 在性能与安全性之间做了平衡。这是Redis默认配置,推荐配置。

2.1.3 AOF重写策略

什么是AOF重写策略?

我们知道AOF存放的是一些对redis的操作,AOF如果过大,我们需要压缩AOF。

AOF如何重写?

redis通过读取当前内存中的数据来重写,基于copy-on-write,全量遍历内存中数据,并不会去操作旧的AOF。比如redis里有100个key的数据,那么我直接往新的AOF文件记录写入这100个key需要的命令就行。(不同数据类型的写操作命令不一样)

流程,

  • fork一个子进程,进行重写操作。
  • 此时新的数据来时,对redis新的写操作将会被主进程继续记录到旧的AOF文件中。
  • 并且主进程将这些命令存到子进程的缓冲区中。
  • 在子进程重写完redis当前的数据内容后。
  • 接着会把自己缓冲区的数据写入到新的AOF文件中。保证新的AOF与Redis内存数据一致。
  • 新的AOF文件改名为旧的AOF文件。完成新旧替换。
  • 因此Redis将会在往子进程缓存写命令时阻塞,和AOF文件改名的时候,阻塞。

思考:为什么要主进程去改名并阻塞主进程对用户的服务?

我认为如果也使用子进程去替换新的AOF时,还接受数据的话,那么这些数据操作不便做记录了。比如list数据结构,我两条push命令,第一条命令还往旧AOF写呢,第二条命令因为AOF更换完毕。写到新的AOF去了,那么不管我使用哪一个AOF文件恢复数据,得出的结果都不对。都只push进一条数据。因此换回收站时再回收垃圾是不可取的。数据撒一地对吧。

思考:为什么只根据Redis当前内存的状态去重写AOF?

我认为有几个方面的原因

1.首先如果根据旧AOF文件压缩,那么我需要分析每条命令,哪些命令可以压缩为一条哪些不可以,这十分耗费cpu资源。

2.操作旧的AOF文件,如果旧的AOF又被插入新的命令,那么是否会造成之前的分析又无效了。浪费cpu资源。和硬盘IO次数。

3.当前Redis内存的状态就是最新的数据,我们需要备份的持久化的就是最新数据状态

4.不论是AOF还是RDB他都是为了持久化内存的数据以免丢失。因此我们持久化当前内存的最新数据以便恢复数据就行。操作旧的AOF并去分析它的命令没有必要。

思考:为什么要fork子进程进行重写操作?

redis中aof_rewrite函数创建新的AOF文件,并进行写入文件数据的操作。进行大量写入操作时,调用此函数的进程将会被阻塞

很长的时间,如果是redis主进程来调用此函数,那么AOF重写过程中,redis服务将不可用。因为Redis是单线程处理用户请求的。它是不能被阻塞太长时间的。

思考:重写开始后,为什么主进程写入旧的AOF命令后,还需要往子进程的缓冲区存一份命令?

如果子进程重写一部分数据后,新的操作如果会修改这些数据。那么重写结束后,新的AOF文件将与内存中的数据不一致。

所以新的操作又必须被写入新的AOF中,但是又不能去读取旧的AOF并分析那些新的redis操作(前面提到了)。所以需要一块区域来存放这些在重写阶段时,用户对Redis的操作。

以上思考我们不仅需要能看懂还要学会其中的设计思维。比如AOF重写策略,里面重写时做出的一些操作,在很多数据备份流程中都能看到。万变不离其中,核心设计思维是不会变的。你备份的时候需要考虑,备份时,进新数据怎么办,放哪,恢复数据时,怎么可以既要恢复备份的数据,也要恢复新的数据。还有copy on write 就更不用说了非常非常多各类的数据读写都会用到这个设计思路。学习的途中要学会归纳总结。找到共性,高中老师常说的话,现在发现有用了。

2.1.4 AOF重写条件

重写分为手动重写和自动重写

手动重写:

通过执行命令: BGREWRITEAOF 执行重写操作。

自动重写:

通过配置文件配置重写条件

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

服务器会记录 前一次AOF文件的大小 aof_current_size

服务器会记录 本次AOF文件的大小  aof_rewrite_base_size

服务器会记录 两次AOF文件增长百分比变量 aof_rewrite_perc

  • 第一个参数auto-aof-rewrite-percentage代表:aof_rewrite_perc超过此参数时,此条件满足重写条件了。
  • 第二个参数auto-aof-rewrite-min-size代表:aof_rewrite_base_size超过此参数时,此条件满足重写条件了。

满足上面两个条件就重写对么?不对

检查所有重写条件是否满足的函数是serverCron,重写还需满足下列条件

  • 没有BGSAVE命令在执行,就是上一次持久化已结束。
  • 没有BGREWRITEAOF在进行,上一次AOF重写已经结束。

 

 

希望大家多多提意见。找出博客中不完善的地方。提出意见和建议,我会选择进行采纳及修改博客不完善的内容并奖励大家。

博客中的大部分内容参考了非常多的其他博客。尽量让博客内容完善,和准确,深浅适中。很多源码级别在博客最后的参考博客中有。因为知道大部分coder辛苦一天不想看到code。所以源码级别的知识还需愿意看的大家多走几步路,访问一下大佬们的源码解析。

别忘了点赞 _(:з」∠)_

 

 

参考博客:

https://blog.csdn.net/u012319493/article/details/83653860

https://blog.csdn.net/jerry1744110/article/details/44832117

https://www.cnblogs.com/itdragon/p/7906481.html

https://blog.csdn.net/Leon_cx/article/details/81545178

https://www.cnblogs.com/ysocean/p/9114268.html

https://redisbook.readthedocs.io/en/latest/internal/aof.html

https://blog.csdn.net/qq_36795474/article/details/82938721

https://shift-alt-ctrl.iteye.com/blog/1878716

https://blog.csdn.net/hezhiqiang1314/article/details/69396887

https://segmentfault.com/a/1190000013113862

 

你可能感兴趣的:(Redis,AOF,RDB,持久化,Redis,详解)