RDB
【问题】Redis是内存数据库,它首先将自己的数据库状态储存在内存里面,如果没有采取措施将数据库状态保存到磁盘中,一旦服务器进程退出,数据库状态也会消失导致数据丢失。RDB持久化能解决这个问题,RDB文件时一个经过压缩的二进制文件,保存在硬盘中,即使服务器故障,只要RDB文件存在就能用它进行数据库状态还原。
-
RDB(保存的是dump.Rdb文件):
在指定的时间间隔内将内存中的数据集【快照】写入磁盘,也就是恢复时将快照文件直接读到内存中(时间段内的内存中的块区数据写入磁盘)
。 -
RDB文件的创建两种命令方式:
1. SAVE命令:SAVE命令会阻塞Redis服务器的进程,直到RDB文件创建完毕为止,在这期间不能处理任何命令请求。
2. BGSAVE命令:派生出一个子进程,然后由子进程负责创建RDB文件,父进程继续处理请求。如果满足以下条件之一就能执行BGSAVE(当然条件能修改):重点!!:服务器在900秒之内,对数据库进行了至少1次修改。 服务器在300秒之内,对数据库进行了至少10次修改。 服务器在60秒之内,对数据库进行了至少10000次修改。 修改次数由专门的dirty计数器来计算,记录从上次更新之后到现在共进行了几次修改。
服务器处理SAVE、BGSAVE、BGREWRITEAOF三个命令的方式和平时不同。
- 服务器会拒绝客户端发送的SAVE命令,禁止SAVE和BGSAVE同时进行的原因是为了避免父进程和子进程都执行相同的调用,防止产生竞争。
- BGREWRITEAOF和BGSAVE不能同时运行,如果BGSAVE在运行,BGREWRITEAOF会被延迟到BGSAVE执行完毕。如果BGREWRITEAOF在执行,BGSAVE命令会被服务器拒绝。这是因为这两个命令实际都是由子进程进行工作,且同时执行大量的磁盘写入操作
。 -
RDB文件的载入是在服务器启动时自动执行的,只要服务器启动并检测到RDB文件的存在,就会自动载入。
-
BGSAVE的具体过程!!!!!
1. Redis单独Fork一个子进程。
2. 子进程会共享主进程的数据空间,并且把共享的数据置为read-only的状态,在这个过程中,子进程会在数据库中创建一个临时文件进行写入。写入采用的是copyOnWrite写时复制,父子进程会共享相同的数据页面,如果此时父进程有写操作,则系统会为父进程要修改的页面创建副本供子进程进行写入,所以子进程的地址空间内的数据是 【fork 时刻】整个数据库的一个【快照】。(fork时刻的数据库快照!!!)
3. 等到fork完之后,将新的RDB文件替换掉旧的RDB文件,并删除旧的RDB文件。 -
RDB文件如何恢复:将备份文件移动到redis安装目录并启动服务
-
RDB的优点:
1. 适合大规模的数据恢复。采用该方式,则数据库中只有一个文件,适合文件备份,通过这种备份,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
2. 性能最大化。对于 Redis 的服务进程而言,在开始持久化时,它唯一需要做的只是 fork 出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行 IO 操作了。
3. RDB是一个非常紧凑的文件,它保存了某个时间点的数据集。 -
RDB的缺点
- 在一定间隔时间做一次备份,如果意外故障,会导致最后一次快照后的所有修改丢失。
- fork时内存中的数据被克隆了一份,导致内存膨胀为原来的大致2倍。
-
如何停止:动态停止 RDB 保存规则的方法:redis-cli config set save “”,或者修改配置文件,重启即可。
AOF
AOF通过以日志的形式来记录每个写操作,将Redis中执行过得到写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,即redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
- AOF持久化功能的实现可以分为命令追加、文件写入、文件同步三个步骤。
- 命令追加:当AOF持久化功能打开的时候,服务器执行完写命令。就会将写命令追加到aof_buf缓冲区下。
- 文件写入和同步:服务器在结束事件循环前,会考虑是否需要将缓冲区中的内容保存到AOF文件中,这个写入的行为和appendfsync选项有关。
当appendfsync的值是always时,每次发生数据变更就会立刻被记录到磁盘,数据完整性比较好,即使丢失也只会丢失一个事件中产生的命令数据。但性能比较差,是三个值中最慢的一个。
当appendfsync的值是eversec时,服务器在每个事件循环都要将aof_buf缓冲区所有内容写入到AOF文件,每隔一秒就在子线程中进行同步,如果出现故障停机,也只会丢失一秒钟的数据。
当appendfsync的值是no时,何时进行AOF同步由操作系统控制,出现故障会导致上次同步的AOF文件之后的所有写命令丢失。 - AOF文件的载入与数据还原过程
- 创建一个不带网络链接的伪客户端。因为AOF文件所使用的命令不需要网络,所以伪客户端执行命令的效果和带网络连接的客户端执行效果一样。
- 从AOF文件中分析并读取出写命令并使用伪客户端执行被读出的写命令。
- 不断重复步骤2知道所有写命令处理完毕。
AOF重写
- 【AOF持久化机制存在的问题】:随着写命令的不断增加,AOF文件中的内容会越来越多,文件体积越来越大,如果不进行控制,体积太大的AOF文件对服务器造成很大的影响,还原时间太长。
- AOF文件重写功能:解决上述问题
AOF文件重写不需要对现有的AOF文件进行任何读取操作,而是通过读取数据库状态来实现的
举个例子:我们对数据库进行了连续多个相同的操作如:LPUSH list A ,LPUSH list B,LPUSH list C
,那么在重写时,会用一条LPUSH list A B C
来替代三条语句。
AOF重写功能的实现原理:从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录的键值对的多条命令。这个过程生成的新的AOF文件只包含还原当前数据库 状态所必须的命令,并不会造成任何的硬盘空间的浪费。
重写触发的条件:Redis会记录上次重写的AOF大小,默认配置是当AOF文件大小是上次重写大小的一倍,且文件大于64M时触发。 - AOF的后台重写
-
上面的AOF重写通过aof_rewrite函数完成,但是这个函数进行大量写入时,线程会被阻塞,因为Redis使用单线程来处理命令请求,这期间就无法进行其他命令请求的处理。这才有了AOF后台重写。
-
后台重写的目的:Redis将AOF重写放入到子进程中进行异步处理
1. 子进程在重写AOF文件期间,父进程能继续处理命令请求。 2. 子进程带有服务器进程的数据副本,使用子进程而不是线程避免使用锁的情况,保证数据的安全性
-
后台重写的问题:在子进程重写期间,服务器还需要继续处理命令请求,而
子进程处理的是子进程生成时的数据库状态快照
,所以有新的写命令对数据库状态进行更改是不会写入到AOF文件中的,这会导致数据不一致的问题。 -
AOF重写缓冲区(BGREWRITEAOF命令的实现原理):AOF重写缓冲区解决这种数据不一致的问题,在服务器创建子进程后开始使用,当Redis执行完一个写命令,它同时会将这个写命令写入到AOF缓冲区和AOF重写缓冲区中。当子进程完成重写工作后,向父进程发送信号,父进程收到信号后,将AOF重写缓冲区的所有内容写入到新的AOF文件中,使数据库状态达到一致。然后对新的AOF进行改名,原子的覆盖现有的AOF文件,完成替换。
-