Redis系列——5.持久化

目录

前言

什么是持久化?

持久化的实现

1.快照(RDB:Redis Database)

a. 简介

b.三种触发方式

2.写日志(AOF:Append only file)

a. 简介

b.三种触发条件

c.AOF重写

前言

hello,小可爱们,咱又见面啦。一日不见,如隔三秋。有没有想偶啊?

好了好了,不闹了,咱今天先来提一个问题,redis之所以速度快,是因为将数据放在内存中。众所周知,存放在内存中的速度是快,但是关闭redis,数据即丢,如断电即丢。

那这样肯定是不行的,比如我上线了一个新的项目,前台页面展示用的是redis中的数据,突然断电了,那我数据咋整,用户看不到数据了,那我肯定GG啦。

开发redis的人也不傻,他们写了一个持久化的方案,将内存中的数据写入到硬盘中,这样数据丢不了。

什么是持久化?

redis持久化就是对数据的更新保存在磁盘上,以便数据恢复。

持久化的实现方式

1.快照(RDB)

a

简介

对数据在某时某点的完整备份。

将数据完整的生成一个快照,以二进制格式保存在硬盘中,后缀为.rdb。当需要进行恢复时,再从硬盘加载到内存中。

b

三种触发方式

save命令触发方式(同步):新生成一个新的临时文件,当save执行完后,用新的替换老的。

如下图,我们看一下dump.rdb上次更新时间是33分,而当前时间是37分,说明他在之前几分钟刚更新过。

接下来,我们执行save命令,强制使他更新备份文件,如下图,当前时间是38分,而rdb文件的更新时间也是38分。

bgsave命令触发方式(异步):与同步相同。

规则自动触发方式(3种触发条件):当某些条件达到时,自动生成rdb文件。

2.写日志(AOF)

a

简介

所有数据更新语句都记录在日志中。

b

三种触发条件

always:让缓冲区的数据及时刷新到硬盘。

everysec:每秒刷新到硬盘,在高写入量下,可以保护硬盘,出现故障可能会丢掉一秒的数据。‘

no:不可控,在不知道啥时候刷新,也不知道丢多少数据。

c

AOF重写

随着时间的流逝,文件越来越大,这主要有两个缺点:一是对服务器的压力越来越大,二是AOF还原数据库状态的时间越来越长。

为了解决这个体积膨胀的问题,redis提供了AOF重写功能,其实也就是创建一个新的AOF文件,新旧文件所保存的数据库状态是相同的,但新文件不会包含任何浪费空间的冗余指令,而且体积比旧文件少很多。

具体是个什么概念呢?我们一起感受一下,如下图,我们先往list的尾部插入A,B,C,D,E,再往删掉A,B,再往尾部插入F,G,最后打印出来,可以知道最终的list为CDEFG。

这样AOF中存储的就是6个语句,因为上面一共7个语句,要去掉查询语句。

我们试想一下,如果我一直操作这几个数据,那他会一直存储我的操作语句,这样AOF文件的体积肯定会越来越大,但数据量其实就这么几个值。如果用很大的空间来存储这么小的数据量,那肯定是不合理的。

那AOF的重写并不是对原来的AOF进行读取和分析,而是通过数据库的状态来实现,现在数据库中一个有5个值,其实也要用一个RPUSH list "C" "D" "E" "F" "G"就可以啦。

下面来看一下AOF重写的伪代码,redis的底层是用C写的,且开源的,先立一个flag,之后看redis的源码,emmmm,希望以后不要打脸。

接下来,我们看一下哪些条件下会触发AOF的重写功能?

显式手动触发

redis客户端向Redis发bgrewriteaof命令,redis服务端fork一个子进程去完成AOF重写。这里的AOF重写,是将Redis内存中的数据进行一次回溯,回溯成AOF文件。而不是重写AOF文件生成新的AOF文件去替换。

AOF重写配置自动触发

auto-aof-rewrite-min-size:AOF文件重写需要的尺寸

auto-aof-rewrite-percentage:AOF文件增长率

redis提供了aof_current_size和aof_base_size,分别用来统计AOF当前尺寸(单位:字节)和AOF上次启动和重写的尺寸(单位:字节)。

AOF自动重写的触发时机,同时满足以下两点:

aof_current_size > auto-aof-rewrite-min-size

aof_current_size - aof_base_size/aof_base_size > auto-aof-rewrite-percentage

这边具体的演示就不写了,其实就是能看出在重写之后,AOF文件的大小比之前小了很多,去除了很多冗余命令。

那我们来想一个问题,因为redis是单线程工作的,那么如果在我手动重写AOF的时候,又有新的命令写入,这个时候怎么办?

很明显,如果我在重写的时候,又要新的命令写入,这个时候是不能写入的,redis也就失去了功能。这肯定不是我们想看到的。

那redis将重写程序放在了子进程中,这样的好处主要有两点:

子进程进程AOF重写的时候,主进程可以继续处理命令要求

子进程带有主进程的数据副本,使用子进程而是线程。

解决了这个问题,新的问题又来了。so,坑是永远填不完的,emmmm,相信偶。

新的问题就是现在是重写的时候,redis可以执行新的命令,那么在重写结束之后,重写的AOF文件与原来的AOF文件对数据库状态的描述是不一样的,因为在重写期间,redis又接受了新的命令,执行了新的命令。

所以redis添加了AOF重写缓存的概念,在重写期间,redis在执行新的命令之后,将命令添加到原来的AOF文件中,同时也将命令添加到AOF重写缓存中,这样在完成重写工作后,再将AOF重写缓存中的命令添加到新的AOF文件中。最后将新的AOF文件重命名,覆盖原来的AOF文件。

这样就解决了数据库不一样的情况,至此,AOF重写完毕。

哎啊,累死了,redis的持久化终于结束了,历经了好几天的晚上,终于把他整理完毕了。

答应偶,一定要看,好吗?

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190124G10J4L00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券