目录
策略
- RDB => Redis DataBase 相当于定期的方式实现持久化
- AOF => Append Only File 相当于实时的方式实现持久化
RDB
RDB定期的把我们Redis内存中的所有数据,都写入硬盘中,生成一个"快照"
Redis给内存中当前存储的这些数据,赶紧拍个照片,生成一个文件,存储在硬盘中~~
后续Redis一旦重启了,就可以根据刚才的"快照"就能把内存中的数据给恢复回来~
"定期"具体来说,又有两种方式:1.手动触发.
程序员通过redis客户端,执行特定的命令,来触发快照生成
save
bgsave
2.自动触发.
在Redis配置文件中,设置一下,让Redis每隔多长时间/每产生多少次修改就触发。
save:执行save的时候,redis就会全力以赴的进行"快照生成"操作,此时就会阻塞redis的其他客户端的命令~导致类似于keys*的效果一般不建议使用save
bgsave:bg=>background 不会影响Redis服务器处理其他客户端的请求和命令
Redis咋做到的?是不是搞了个多线程啥的?
并非如此!!
并发编程的场景.此处redis使用的是"多进程"的方式,来完成的并发编程,来完成的bgsave的实现。
bgsave执行流程
1.判断当前是否存在其他正在工作的子进程。
比如现在已经有一个子进程正在执行bgsave,此时就直接把当前的bgsave返回~
2.如果没有其他的工作子进程,就通过fork这样的系统调用创建一个子进程来~
fork是linux系统提供的一个创建子进程的api(系统调用)
fork创建子进程,简单粗暴,直接把当前的进程(父进程)复制一份,作为子进程~
一旦复制完成了,父子进程就是两个独立的进程,就各自执行各自的了~~
3.子进程负责进行写文件,生成快照的过程.
父进程继续接收客户端的请求,继续正常提供服务.
4.子进程完成整体的持久化过程之后,就会通知父进程,干完了,父进程就会更新一些统计信息,子进程就可以结束销毁了。
RDB效果演示
rdb文件中的数据,不是你这边插入了数据,就会立即更新的!!
1.手动执行save&bgsave触发一次快照
由于我们的数据比较少,执行bgsave瞬间就完成了,立即查看应该就是有结果的.如果以后我们接触的数据多了,执行bgsave就可能需要消耗一定的时间,立即查看不一定就是生成完毕了~
通过上述操作,就可以看到,redis服务器在重新启动的时候,加载了rdb文件的内容,恢复了内存中之前的状态。
2.插入新的key,不手动执行bgsave
发现没有,重新启动redis服务器
发现就有了,redis生成快照操作,不仅仅是手动执行命令才触发,也可以自动触发!!
1)通过刚才配置文件中save执行M时间内,修改N次
2)通过shutdown命令(redis里的一个命令)关闭redis服务器,也会触发。
3)redis进行主从复制的时候,主节点也会自动生成rdb快照,然后把rdb快照文件内容传输给从节点
如果是通过正常流程重新启动redis服务器,此时redis服务器会在退出的时候,自动触发生成rdb操作,但是如果是异常重启(kill -9 或者 服务器掉电)此时redis服务器来不及生成rdb,内存尚未保存到快照中的数据,就会随着重启而丢失~
3.bgsave操作流程是创建子进程,子进程完成持久化操作.
持久化会把数据写入新的文件中,然后使用新的文件替换旧的文件.
liunx文件系统.
文件系统典型的组织方式(ext4)主要是把整个文件系统分成了三个大的部分
1.超级块(放的是一些管理信息)
2.inode区(存放inode节点,每个文件都会分配一个inode数据结构,包含了文件的各种元数据)
3.block区,存放文件的数据内容了。
4.通过配置自动生成rdb快照
执行FLUSHALL也会清空rdb文件
5.如果把rdb文件,故意改坏了,会咋样?
手动的把rdb文件内容改坏.
然后一定是通过kill进程的方式,重新启动redis服务器.
如果通过service redis-server restart重启,就会在redis服务器退出的时候,重新生成rdb快照。
就把咱门刚才改坏了的文件给替换了~~
RDB优缺点
-
RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据快照。非常适用于备份,全量复制等场景,比如每6小时执行bgsave备份,并把RDB文件复制到远程机器或者文件系统中用于灾备。
-
Redis加载RDB恢复数据远远快于AOF的方式。
-
RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork创建子进程,属于重量级操作,频繁执行成本过高。
-
RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个RDB版本,兼容性可能有风险。
AOF
类似于mysql的binlog,就会把用户的每个操作,都记录到文件中。
当redis重新启动的时候,就会读取这个aof文件中的内容,用来恢复数据~
开启aof的时候,rdb就不生效了~
启动的时候不再读取rdb文件内容了~
aof默认一般是关闭状态,修改配置文件,来开启aof功能~
AOF是一个文本文件.
每次进行的操作,都会被记录到文本文件中~
通过一些特殊符号作为分隔符,来对命令的细节做出区分~
AOF缓冲区刷新策略
实际上,是没有影响的!并没有直接影响到redis处理请求的速度~
1.AOF机制 并非是直接让工作线程把数据写入硬盘,而是先写入一个内存中的缓冲区,积累一波之后,再统一写入硬盘
2.硬盘上读写数据,顺序读写的速度是比较快的
随机访问则速度是比较慢的。
AOF是每次把新的操作写入到原有文件的末尾,属于顺序写入~
如果把数据写入到缓冲区里,本质还是在内存冲呀~
万一这个时候,突然进程挂了,或者主机掉点了,咋办?是不是缓冲区中的数据就丢了??
是的!!缓冲区中没来得及写入硬盘的数据是会丢的~
redis给出了一些选项,让程序员,根据实际情况来决定怎么取舍~缓冲区的刷新策略 ~
刷新频率越高,性能影响就越大,同时数据的可靠性就越高.
刷新频率越低,性能影响就越小,同时数据的可靠性就越低.
AOF的重写机制
AOF文件持续增长,体积越来越大~
会影响到,redis下次启动的启动时间~
redis启动的时候要读取aof文件的内容
注意!!上述aof中的文件,有一些内容是冗余的!
redis存在一个机制,能够针对aof文件进行整理操作。这个整理就能够剔除其中的冗余操作,并且合并一些操作,达到给aof文件瘦身这样的效果。 重写机制~
AOF重写机制的触发机制
- 手动触发:调用bgrewriteaof命令
- 自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机
AOF重写流程
创建子进程fork
父进程仍然负责接收请求.
子进程负责针对aof文件进行重写~
注意!重写的时候,不关心aof文件中原来都有啥~
只关心内存中最终的数据状态~
子进程只需要把内存中给当前的数据,获取出来,以AOF的格式写入一个新的AOF文件中!!
此处子进程写数据的过程,非常类似于RDB生成一个镜像快照~
只不过RDB这里是按照二进制的方式生成的
AOF重写,则是按照AOF这里要求的文本格式来生成的.
子进程写新aof文件的同时,父进程仍然在不停的接收客户端新的请求。
父进程还是会写把这些请求产生的AOF数据写入到缓冲区,再刷新到原有的AOF文件里~
子进程这边,把aof数据写完之后,会通过信号通知一下父进程,父进程再把aof_rewrite_buf缓冲区中的内容也写入到新AOF文件里~
混合持久化
AOF本来是按照文本方式来写入文件的.
但是文本的方式写文件,后续加载的成本是比较高的~
redis就引入了"混合持久化"的方式,结合了rdb和aof的特点~
按照aof的方式,每一个请求/操作,都记录入文件。在触发aof重写之后,就会把当前内存的状态按照rdb的二进制格式写入到新的aof文件中。
后续再进行的操作,仍然是按照aof文本的方式追加到文件后面。
这个选项为yes就是开启混合持久化。
同时存在aof和rdb快照,以谁为主?
以aof为主!
信号
信号这个东西,可以认为是Linux的神经系统~
进程之间的互相作用
但是Java生态并不鼓励使用多进程模型编程~
信号能表达的信息有限,并非像socket这样的方式可以传输任意的数据~
因此,像上述父子进程场景中,子进程表达"我干完了"