RDB持久化
什么是RDB
- RDB持久化是记录当前时间节点内的Redis
**快照信息**
,可以根据快照信息可以用于Redis的**恢复**
,主从模式的**第一次同步**
- 主进程会
**fork**
出一个子进程,子进程进行RDB文件的生成,当主进程正在进行读操作时,则会与子进程一起读取公共内存中的内容。当主进程正在进行写操作时,则会将内容拷贝一份进行操作,不影响子进程的RDB操作。 - 子进程完成新的RDB文件写入完成后,删除原有的RDB文件
RDB的触发条件
**save**
利用**主进程**
进行RDB的备份,会阻塞所有请求**bgsave**
fork出**子进程**
进行RDB操作,此时仍可以处理其他请求- 当Redis关闭时,会自动触发一次RDB操作,用于重启时的数据恢复
- 当Redis的请求次数达到设定的若干条件 设置的规则为 xxx秒内有多少条数据修改的请求
AOF持久化
什么是AOF
- 在Redis
**执行命令后**
,都会将操作记录到**AOF缓冲区**
中,然后再**write**
写到**Page Cache**
中 - 只有调用了
**fsync**
进行持久化到磁盘后,文件才真正持久化完成,如果在fsync执行之前,机器宕机,则这部分的AOF日志会丢失
AOF的基本流程
- 当Redis执行完一条写操作指令后,会将该命令追加(append)到
**AOF缓冲区**
中 - 在加入到缓冲区后会同时调用写入(
**write**
)命令,将AOF缓冲区的数据写入到中**内核缓冲区**
(Page Cache) - 参数包含
**三种**
选项,**每次write**
都进行fsync刷盘,**后台线程每秒钟**
执行一次fsync刷盘,和不主动刷盘,有操作系统自行决定何时刷盘(大约30秒) - 每次write操作之后都进行刷盘则过于浪费系统资源,一般设定为后台线程
**每秒钟执行一次fsync刷盘**
操作 - 当AOF文件过大时会进行
**文件重写**
,重写是耗费资源的过程,因此会创建子进程进行AOF的重写操作,这里的重写操作只记录每个key最后一次的操作,因此可以在保证与原AOF文件语义相同的情况下减少大量的空间,在原AOF文件重写完毕后,再把新的缓存文件加入到重写后的AOF文件中 - 当系统重启时,通过
**load**
进行AOF文件来恢复数据 - 如果每次执行完一句写语句就写入磁盘,则是随机IO并且一次只操作一条数据。
- 现在通过
**WAL机制**
,将**随机IO**
改为**顺序IO**
,并且把**单条语句的操作**
改为**批量操作**
,提高性能。
RDB和AOF的区别
RDB的优势
**RDB**
是对整个Redis的快照保存的是**二进制数据**
,**文件体积较小**
,而**AOF**
的文件记录的是**每一条指令**
,**文件体积较大**
- RDB记录的是实际的数据集,而AOF记录的是实际的操作,因此在恢复的过程中,
**RDB的恢复速度比AOF要快很多**
AOF的优势
- RDB需要开启子进程同时对整个Redis进行文件的写入保存,虽然这个操作可以由子进程在后台异步执行,但是仍然是一个非常耗费资源的操作,而AOF可以以较低的消耗保证秒级的信息丢失
- 不同版本的Redis中有对应不同的RDB格式文件,不同的Redis版本中可能会不兼容
- AOF的日志可以进行解析
主从模式信息同步
主从同步会从读库中读到旧数据吗
- 根据不同的版本和命令情况,可能会从读库中读到旧数据
- 在Redis 3.2之前,在从库中读取数据时不会判断该key是否过期,因此可能从读库中查询到过期的key
- 在Redis3.2之后,在从库中读取数据时会先判断该key是否已经过期,如果过期则会将该key设置为null,并且返回null
- 如果是主库中的命令执行的是 通过
**expire**
添加过期时间,则添加的是**ttl**
值,即是当前时间节点添加ttl后为最终的过期时间。从主库将命令同步过来时会导致,主库中的key已经过期了,但从库中的key还没有过期。 - 使用
**expireAt**
命令可以解决这个问题,同样是设置过期时间,但是expireAt设定的是指定的时间戳,因此主库和从库的信息会同时过期,因此不会在从库中读取到过期的信息。
SYNC 同步
- master节点会为每个slave节点开辟一块空间,replication buffer(复制缓冲区)用于存储每个slave节点在生成RDB文件后的写命令,占用空间
- slave在加载RDB文件时,无法对外提供读操作
- 在每次slave与Master节点断开连接后,无论什么原因都需要进行全量同步,全量同步的bgsave操作是非常耗费时间的。
PSYNC 同步
- 相比于SYNC同步,因网络问题短暂与Master节点断开连接后,可以通过runId查询到是否相等,如果Master中有缓存对应的数据,则只需要进行增量同步
- 但是当slave突然被宕机或重启时,或是Master节点宕机,重新选取Master节点后,这些情况都会导致runId和offset发生改变,因此需要重新进行全量同步。
PSYNC 2.0
PSYNC2.0的优化
- 相比于PSYNC进行优化,在出现了选举出新Master的情况,在PSYNC2.0中仍然有可能执行增量同步。在PSYNC2.0中使用 replid和replid2代替了原有的runId
- slave节点中的replid是当前正在同步的Master节点的replid,replid2是上一个Master节点的replid
- Master节点中的replid是就是自己的复制id,在初始时,replid2为空,当发生主从切换后,新的Master节点的replid2则会上一个正在同步的Master的replid
- 在Master节点宕机后,可以通过replid属性判断Slave和新Master之前是否所属同一个Master节点,如果是则可以进行增量同步
全量同步的具体过程
- Slave节点像master节点发出增量同步请求,会带上 replid和offset
- replid代表数据集,相同的数据集他们的replid是相同的
- Master判断 请求中的replid与自己的是否相同,如果不相同,或Offset不符合要求则说明是第一次进行全量同步,并将Master节点的replid和offset发送给slave节点
- slave收到后保存信息,此时slave节点的replid和offset和上一版本的Master节点相同
- Master确认要进行全量同步,此时会fork一个子进程开始进行 bgsave 备份RDB文件,同时会将在RDB进行时收到的所有命令保存到repl_baclog中
- Master将RDB文件发送给Slave,slave节点清空所有原始数据,利用RDB文件进行恢复
- Master将repl_baclog发送给Slave,Slave执行log中保存的命令
增量同步
什么时候回出现增量同步
除了Slave第一次对Master进行全量同步和与Master断开连接过久外,其余的同步都是增量同步
增量同步的具体过程
- Slave节点像Master节点发出增量同步的请求,发送Slave节点的replid和offset
- Master节点判断出请求的replid与Master节点相同,并且offset符合要求,于是给slave节点回复continue
- Master节点将Slave节点后的数据发送给Slave节点,Slave执行命令从而同步数据。
repl_backlog_buffer 中保存的信息
- repl_backlog_buffer 是一个数组,Master会循环的进行信息的写入
- Master在一直进行写入时,slave也在一直进行读取,与复制缓冲区会为每个slave分配一块内存不同的是,repl_backlog_buffer是所有slave共用一个的
- 当写完一圈后,会继续覆盖先前以后得数据继续写入
- 但是当slave节点由于网络问题或其他问题,导致一段时间没有进行增量同步,master节点覆盖了slave节点,此时则需要进行全量同步