《Redis设计与实现》读书笔记——Redis数据持久化之RDB、AOF

持久化简介

Redis是内存数据库,如果服务器突然宕机,那么存储在内存中的数据就会全部丢失,因此必须要有一套机制来保证Redis的数据不会因为故障丢失,这种机制就是Redis的持久化,它将内存中的数据库状态保存到磁盘中。

持久化发生了什么?

  1. 客户端向数据库发送写命令
  2. 数据库接收到客户端的写请求
  3. 数据库调用系统API将数据写入磁盘
  4. 操作系统将写缓冲区传输到磁盘控制器
  5. 操作系统的磁盘控制器将数据写入实际的物理媒介

并不是所有的写操作都是立即写入磁盘的,而是需要先经过一个先缓冲区,Linux将在30秒后实际提交写入,但是30秒并不是Redis能接受的,这意味着,如果发生故障,那么最近30秒的写入的所有操作都会丢失 -> 使用fsync命令可以强制内核将缓冲区写入磁盘,但这是一个非常消耗新能的操作,每次调用都会阻塞等到设备报告IO完成,所以一般在生产环境的服务器中,Redis通常是每隔一秒执行fsync操作

RDB

RDB可以生成一个Redis快照,RDB文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态。

有两个命令可以用于生成RDB文件,一个是SAVE一个是BGSAVE。

  • SAVE命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞的期间,服务器不能处理任何命令请求。
  • BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求。
  • 服务器状态中会保存所有用save选项设置的保存条件,当任意一个保存条件被满足时,服务器会自动执行BGSAVE命令
save 900 1 服务器在900秒内,对数据库进行了至少1次修改
save 300 10 服务器在300秒内,对数据库进行了至少10次修改
save 60 10000 服务器在60秒内,对数据库进行了至少10000次修改

为了保证在生成RDB文件期间服务器还是能正常接收客户端请求,以及解决内存数据结构变化的问题。

使用系统多进程COPY ON WRITE 机制 | fork 函数
在这里插入图片描述
操作系统多进程的COW机制,Redis在BGSAVE时会fork出一个子进程,主进程和子进程会共享内存里面的代码块和数据块。
fork创建子进程的过程:

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝到子进程
  • 添加子进程到系统进程列表
  • frok函数返回,开始调度器调度。

子进程会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化到磁盘中,但是父进程不一样,它必须持续服务客户端请求,然后对内存数据结构进行不断的修改

这时候就会使用操作系统的COW进行数据段分离,数据段是由很多操作系统的页面组合而成的,当父进程对其中一个页面的数据进行修改的时候,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改这时候子进程相应的页面是没有变化的,还是进程产生时那一瞬间的数据。

另外:

  1. 如果服务器开启了AOF持久化功能,那么服务器会有优先时候AOF文件来还原数据库
  2. 只用AOF持久化功能处于关闭状态的时候,服务器才会使用RDB文件来还原数据库状态。
  3. 在BGSAVE命令的是执行期间,客户端发送的SAVE命令会被服务器拒绝
  4. BGSAVE 和 BGREWRITEAOF 两个命令也不能同时执行
  5. 如果BGSAVE命令正在执行,那么客户端发送的BGREWRITEAOF命令会被延迟到BGSAVE命令执行完毕之后执行
  6. 如果BGREWRITEAOF命令正在执行,那么客户端发送的BGSAVE命令会被服务器拒绝
  7. 因为BGREWRITEAOF和BGSAVE两个命令实际工作都是由子进程去执行的,所有已这两个命令在操作方面并没有什么冲突的地方,不同同时执行他们只是一个性能方面的考虑-并不出两个子进程,并且这两个子进程都同时执行大量的磁盘写入操作,会相当耗费性能。

AOF

与RDB持久化通过保存数据库中的键值对来记录数据库状态不同的是,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。

AOF持久化功能的实现可以分为命令追加、文件写入、文件同步三个步骤。

  • 命令追加
    当AOF持久化功能处于打开状态的时候,服务器在执行完一个写命令之后,会议协议的格式将被执行的写命令追加到aof_buf缓冲区的末尾。
  • AOF文件的写入和同步
    因为服务器在处理文件事件的时候可能会执行写入命令,使得一些内容被追到到aof_buf缓冲区里面,所以在服务器每次结束一个事件循环之前,都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区中的内容写入和保存到AOF文件里面。

flushAppendOnlyFile函数的行为由服务器配置的appendfsync选项的值来决定

  • always: 服务器在每个时间循环都要将aof_buf缓冲区中的所有内容都写入到aof文件中,并且同步AOF文件,所有always的效率是最慢的一个,但是安全性来说,即使出现故障停机,也只会丢失一个时间循环中所产生的命令数据
  • everysec : 服务器在每个时间循环都要将aof_buf缓冲区中的所有内容都写入到AOF文件中,但是是每隔一秒钟就要对AOF文件进行一次同步,即使出现故障,数据库也之丢失一秒钟的命令数据(默认)
  • no:服务器还是每个时间循环都要将aof_buf缓冲区的中的所有内容写入AOF文件,至于何时对AOF文件进行同步,则由操作系统控制,因为处于no模式下的调用无需同步的操作,所以该模式下的AOF文件写入速度总是最快的,不过因为这种模式会在系统缓存中积累一段时间的写入数据,所以该模式的单次同步时长是三种模式中时间最长的。

在AOF数据还原中,Redis会创建一个不带网络连接的伪客户端,从AOF文件中分析并读取出一条写命令

AOF重写

因为AOF持久化是通过保存被执行写命令来记录数据库状态的,随着服务器运行时间的流逝,AOF文件中的内容会越来越多,体积过大的AOF文件很可能对服务器造成影响,使用AOF文件来进行数据还原所需的时间就越多。

rpush list "A" "B"
rpush list "C"
rpush list "D" "E"
lpop list
lpop list
rpush list "F" "G"

aof重写原理 : 可以用 rpush list “C” “D” “E” “F” "G"替代者6条命令

BGREWRITEAOF

Redis 提供了 bgrewriteaof 指令用于对 AOF 日志进行瘦身。其 原理 就是 开辟一个子进程 对内存进行 遍历 转换成一系列 Redis 的操作指令,序列化到一个新的 AOF 日志文件 中。序列化完毕后再将操作期间发生的 增量 AOF 日志 追加到这个新的 AOF 日志文件中,追加完毕后就立即替代旧的 AOF 日志文件了,瘦身工作就完成了。

在这里插入图片描述

RDB AOF 比较与混合持久化

RDBAOF
启动优先级
体积
恢复速度
数据安全性丢数据根绝策略决定

如果仅仅使用RDB恢复内存状态可能会丢失大量的数据,如果仅仅使用AOF的话,重放AOF日志性能也相对较慢,这样在Redis实例很大的情况下,启动需要花费很长的时间。

Redis4.0为了解决这个问题,支持混合持久化,在Redis启动的时候,先加载RDB的内容,然后重放增量AOF日志。

参考 :
《Redis设计与实现》
Redis(7)——持久化【一文了解】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值