Redis RDB和AOF持久化机制详解「建议收藏」

Redis RDB和AOF持久化机制详解「建议收藏」Redis支持RDB和AOF两种持久化机制,持久化功能有效的避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化文件即可实现数据恢复

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」。

概念

Redis支持RDB和AOF两种持久化机制,持久化功能有效的避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化文件即可实现数据恢复

RDB

Redis提供RDB持久化功能,RDB持久化是把Redis 数在内存中的数据生成快照保存到硬盘的过程,触发RDB持久化过程分为手动触发和自动触发。

RDB持久化生成的RDB文件是一个经过压缩的二进制文件,通过这个文件可以还原生成RDB时数据库当时的完整数据,从而实现数据持久化,避免数据丢失。

RDB文件的创建和载入

RDB文件创建基本概念

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

SAVE命令会阻塞Redis服务进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求。

image.png

当SAVE命令正在执行时,客户端发送的所有命令请求都会被拒绝,只有在服务器执行完SAVE命令,重新开始接受命令请求之后,客户端发送的命令才会被处理。

BGSAVE命令不会阻塞服务器进程,BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程继续处理命令请求,在BGSAVE命令执行期间,客户端发送的SAVE,BGSAVE命令都会被拒绝。

image.png

创建RDB文件实际是由rdbsave函数来完成,save和bgsave命令会以不同的方式调用这个函数。

文件载入

RDB文件载入是在服务器启动时自动执行的,只要Redis服务器在启动时检测到RDB文件存在,就会自动载入到RDB文件。我们来看下Redis启动时打印的日志文件

image.png

DB loaded from disk 就是服务器在成功载入RDB文件之后打印的。

这里要强调一下,因为AOF文件更新频率通常比RDB文件更新频率高,所以如果服务器开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据,只有在AOF关闭时,才会使用RDB文件来还原数据。

载入RDB文件实际是由rdbload函数来完成。

服务器在载入RDB文件期间,会一直处于阻塞状态,直到载入工作完成。

自动保存

因为BGSAVE命令不会阻塞主服务器进程,所以Redis允许用户通过设置服务器配置的save选项,让服务器自动每隔一段时间执行一次BGSAVE命令。

image.png

  • 服务器在900秒之内对数据库进行了至少一次修改。

  • 服务器在300秒之内对数据库进行了至少10次修改。

  • 服务器在60秒之内,对数据库进行了至少10000次修改。

只要满足这三个条件的任意一个,BGSAVE命令就会被执行。

如果用户没有主动设置save选项,服务器就会为save选项设置默认条件,上图展示的就是默认条件。

自动保存

服务器会根据save选项设置的保存条件,设置服务器状态redisServer结构的saveparams属性

image.png

saveparams属性是一个数组,数组中的每个元素都是一个saveparam结构,每个saveparam结构都保存了一个save选项设置的保存条件。

image.png

除了saveparams数组之外,服务器状态还维持着一个dirty计数器和一个lastsave属性。

dirty计数器用来记录距离上一次成功执行SAVE命令或者BGSAVE命令之后,服务器对数据库状态进行了多少次修改。

lastsave属性是一个UNIX时间撮,记录了服务器上一次成功执行SAVE命令或者BGSAVE命令的时间。

服务器每成功执行一次数据库修改命令,dirty计数器会进行更新,修改多少次数据库dirty值就会增加多少。

Redis的服务器周期性操作函数serveCron默认每隔100毫秒执行一次,会检查save选项设置的保存条件是否已经满足,如果满足,就执行BGSAVE命令。

RDB文件结构

image.png

RDB文件基本上就是由这五个部分组成。

  • REDIS:RDB文件开头是REDIS部分,保存着”REDIS”五个字符。通过这5个字符,程序在载入文件时,可以快速检查所载入的文件是否是RDB文件。

  • db_vsersion长度是4字节,它的值是一个字符串表示的整数。记录了RDB文件到版本号。

  • databases:包含着零个或多个数据库,以及各个数据库中的键值对数据。

  • EOF常量的长度为1字节,这个常量标志着RDB文件正文内容的结束,当程序读入这个值,就代表所有键值对数据已经加载完毕。

  • check_sum是一个8字节长的整数,保存着一个校验和,这个校验和是程序通过对REDIS,db_version,databases、EOF四个部分的内容进行计算得出的。服务器载入RDB文件时会将载入数据时计算的校验和与check_sum进行对比,来检查RDB文件是否有出错。

image.png

databases部分

这里重点说下databases部分,如果服务器的0号数据库和3号数据库非空,那么服务器将创建一个下图所示的RDB文件

image.png

每个非空的数据库都是由SELECTDB、db_number、key_value_pairs三个部分组成

image.png

  • SELECTDB:长度为1字节,当程序遇到这个值,就知道接下来要读入的将是一个数据库号码

  • db_number:保存着一个数据库号码,当程序读入这个db_number,服务器会调用SELECT命令,根据读入的数据库号码进行数据库切换,使得之后读入的键值对可以载入到正确的数据库中。

  • key_value_pairs:保存了数据库的所有键值对数据,如果键值对带有过期时间,这个过期时间也会和键值对保存在一起。

不带过期时间的键值对在RDB文件中由TYPE、key、value三部分组成

带过期时间的键值对由EXPIRETIME_MS,ms,type,key,value组成。

type记录了value的类型,EXPIRETIME_MS是个常量,1字节,它告知程序接下来要读入的是一个以毫秒为单位的过期时间。

ms是一个8字节长的带符号整数记录了一个亿毫秒为单位的时间戳。

回顾

image.png

AOF

AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态。

AOF持久化实现

命令追加

当AOF持久化功能处于打开状态时,服务器在执行完一个写命令后,会以Redis的协议格式将被执行的写命令追加到服务器中的aof_buf缓冲区的末尾。

写入与同步

Redis的服务器进程是一个事件循环,在服务器每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区的内容写入和保存到AOF文件里面。

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

image.png

always:命令写入aof_buf后调用系统fsync操作同步到AOF文件,fsync完成后线程返回  

everysec:命令写入aof_buf后调用系统write操作,write完成后线程返回。fsync同步文件操作由专门线程每秒调用一次  

no:命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步,同步硬盘操作由操作系统负责,通常同步周期最长30s  

配置为always时,每次写入都要同步AOF文件,在一般的SATA硬盘上,Redis只能支持大约几百TPS写入,显然跟Redis高性能特性背道而驰,不建议配置。  

配置为no,由于操作系统每次同步AOF文件的周期不可控,而且会加大每次同步硬盘的数据量,虽然提升了性能,但数据安全性无法保证。   

配置为everysec,是建议的同步策略,也是默认配置,做到兼顾性能和数据安全性。理论上只有在系统突然宕机的情况下丢失1秒的数据。

重写

随着命令不断写入,会导致aof文件越来越大,文件体积会越来越大,体积过大的AOF文件很可能对Redis服务器甚至整个计算机造成影响,为了解决这个问题,Redis提供了AOF文件重写功能,通过该功能,Redis服务器会创建一个新的AOF文件来替代现有AOF文件,新的AOF文件不会包含任何浪费空间的冗余命令,所以新的AOF文件体积会比旧AOF文件体积要小的多。

重写具体实现

AOF文件重写不需要对现有AOF文件进行任何读取,分析或者写入操作,这个功能是通过读取服务器的数据库内容来实现,考虑以下情景

image.png

为了记录animals键值,AOF文件必须保存上面列出的四条命令。

而当AOF文件重写时,服务器会直接通过读取当前animals键的值,生成一条sadd animals “Dog” “Panda” “Tiger” “Lion” “Cat” 命令来代替上面的四条命令,这样就将保存animals键所需命令从四条减少到一条了。

AOF后台重写

AOF重写会进行大量写入操作,所以为了避免因为重写造成服务器被阻塞,Redis服务器会使用子进程来进行执行,子进程进行AOF重写期间,服务器进程可以继续处理命令请求。

使用子进程也会存在一个问题,因为子进程重写期间,服务器进程会继续处理命令请求,新的命令会对现有数据库内容进行修改,从而造成当前数据库内容和重写后的AOF文件内容不一致。

为了解决这个问题,Redis服务器设置了AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区。

从创建为AOF重写的子进程开始,服务器执行的所有写命令都会被记录到AOF重写缓冲区中。

当子进程完成AOF重写之后,会向服务器进程发送一个信号,服务器进程接收到这个信号会做两件事

  • 将AOF重写缓冲区的所有内容写入到新的AOF文件

  • 将新的AOF文件进行改名,原子性的覆盖旧的AOF文件

image.png

回顾

image.png

RDB和AOF对比

image.png

  • RDB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令。但是由于AOF的优先级更高,因此当AOF开启时,Redis会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会在Redis服务器启动时检测RDB文件,并自动载入。服务器载入RDB文件期间处于阻塞状态,直到载入完成为止。

事务

事务主要的几个命令

  1. multi

事务命令执行的开始,当执行这个命令后,接下来所有的redis命令会存入一个队列当中,不会立即执行,只有当执行exec后,所有的命令会按照进入队列的命令先后执行

  1. exec

事务命令的结束,当执行这个命令时,会把先前进入队列的命令一一执行

3.watch

watch 命令是给键加监控,如果在当前事务中,该键发送了更改,则最终就不会去执行。会返回空

4.DISCARD

清除所有先前在事务中的命令

  1. unwatch

清除所有先前监控的键

示例

image.png

image.png

watch命令原理

带有watch命令的事务会将客户端和被监控的键在数据库中的watched_keys字典中进行管理,当键被修改时,程序会将所有监视被修改键的客户端的redis_dirty_cas 标志打开。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13055.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注