目录
一.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也会将内存的数据持久化。
RDB通过将Redis当前的所有数据生成一个快照(Snapshoting),存储在硬盘中。快照文件默认为dump.rdb
当Redis重启后,Redis会去读取这个快照,并恢复数据。
好比一个黑板(内存),会有很多人去写它,某一瞬间,我把整块黑板拍下来(持久化)。
当黑板被擦掉,我可以迅速通过照片,恢复黑板上的数据。
上面那块黑板我不能太频繁拍照,必须有对应的触发机制。
redis中有如下的5种触发机制:
采用LZF的压缩方式,LZF压缩:
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 ""即可。
dir ./
dbfilename dump.rdb
rdbcompression yes
RDB快照存储后可以设置是否校验数据(CRC64算法):通过redis.conf中的rdbchecksum设置,默认为yes,会增加约10%的性能消耗。
rdbchecksum yes
stop-writes-on-bgsave-error yes
AOF通过将redis每次执行的修改命令记录到单独的日志文件(appendonly.aof),Redis回复数据的时候通过再次执行一遍日志中的命令来恢复数据。
好比这个黑板,我记录每次在上面写数据的操作,当需要再次恢复数据,我参考之前记录的操作再操作一遍就是了
可以查看下图运行的图片,以及aof文件中redis写入的日志信息。
我们可以看见如果对redis的操作分为 读-写操作,这里aof会记录对redis的写操作,这里的写操作并非只说是往里面写入数据的操作(set)。删除,修改也算是写操作。此写非彼写。很多博客里没有指明,容易出现误解。这里特别指明一下。并且这里注意一下读操作。get 以及其他数据格式的读都是不做记录的。
同步策略指将对redis的写命令同步到日志中。也就是持久化到硬盘中。
在redis.conf中配置(windows下的配置文件为redis.windows.conf)
补充知识:
redis的操作分两步,先写操作,然后将内存中的数据同步到磁盘中。
Redis会调用操作系统中的write函数和fsync函数,分别对应redis操作中的写操作和同步操作。
在现代操作系统中,操作系统通常将数据缓存在内存缓冲区中,当缓冲区写满或超过未同步的时限后,系统才把缓冲区写入硬盘。当然未同步的数据如果系统宕掉,这些数据就丢失了。因此操作系统提供fsync函数让应用程序立即同步数据到硬盘。
什么是AOF重写策略?
我们知道AOF存放的是一些对redis的操作,AOF如果过大,我们需要压缩AOF。
AOF如何重写?
redis通过读取当前内存中的数据来重写,基于copy-on-write,全量遍历内存中数据,并不会去操作旧的AOF。比如redis里有100个key的数据,那么我直接往新的AOF文件记录写入这100个key需要的命令就行。(不同数据类型的写操作命令不一样)
流程,
思考:为什么要主进程去改名并阻塞主进程对用户的服务?
我认为如果也使用子进程去替换新的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 就更不用说了非常非常多各类的数据读写都会用到这个设计思路。学习的途中要学会归纳总结。找到共性,高中老师常说的话,现在发现有用了。
重写分为手动重写和自动重写
手动重写:
通过执行命令: 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
满足上面两个条件就重写对么?不对
检查所有重写条件是否满足的函数是serverCron,重写还需满足下列条件
希望大家多多提意见。找出博客中不完善的地方。提出意见和建议,我会选择进行采纳及修改博客不完善的内容并奖励大家。
博客中的大部分内容参考了非常多的其他博客。尽量让博客内容完善,和准确,深浅适中。很多源码级别在博客最后的参考博客中有。因为知道大部分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