个人主页 : 个人主页
文章目录
前言
redis是一个内存数据库,把数据存储在内存中的,而内存中的数据是不持久的,要想能够做到持久,就需要让redis把数据存储到硬盘上。但redis相比于mysql这样的关系型数据库,最明显的特点就是效率高,速度快。这样便导致redis为了保证速度快,数据要存储在内存中,又为了持久化,数据要存储到硬盘中;
当要插入一个新的数据时,需要把这个数据,"同时"写入到内存和硬盘;当要查询某个数据时,直接从内存读取;硬盘数据只是在redis重启的时候,用来恢复内存中的数据的。
redis支持RDB(Redis DataBase)和AOF(Append Only File)两种持久化机制
RDB
RDB定期的把redis内存中的所有数据,都给写入硬盘中,生成一个快照;之后redis一旦重启,就可以根据刚才的快照,把内存中的数据恢复回来。
定期具体而言,又两种方式:手动触发,自动触发
- 手动触发
save命令,阻塞当前redis服务器,直到RDB过程完成为止。会导致类似于 keys *的后果,一般不建议使用save
bgsave命令,redis进程执行 fork 操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束;阻塞只发生在fork阶段
redis内部所有涉及到RDB的操作都采用类似bgsave的方式
2.自动触发在redis配置文件中(linux中,redis的默认配置文件路径是/etc/redis/redis.conf),设置下,使redis每隔多长时间和每产生多少次修改就触发
使用save配置,如"save m n"表示 m秒内数据集发送了 n 次修改,自动RDB持久化;
通过shutdown 命令,关闭redis服务器,也会触发 service redis-server restart ,正常关闭
redis 进行主从复制的时候,主节点也会自动生成RDB快照,然后把RDB快照文件内容传输给从节点
bgsave命令的运行流程
- 执行bgsave命令,redis父进程判断当前进程是否存在其它正在执行的子进程,如RDB/AOF子进程,如果存在bgsave命令直接返回
- 父进程fork完成后,bgsave命令会返回"Background saving started" 信息并不再阻塞父进程,父进程可以继续响应其它命令
- 子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换
- 子进程发送信号给父进程表示完成,父进程更新统计信息
redis生成的rdb文件,存放在redis的工作目录中的,可以在redis配置文件中,进行设置
dump.rdb就是rdb机制生成的镜像文件,redis服务器默认的就是开启rdb的;dump.rdb文件就是二进制文件,把内存中的数据,以压缩的形式(默认采用LZF算法),保存到这个二进制文件中。
后续redis服务器重新启动,就会尝试加载这个rdb文件,如果发现格式错误,可能会加载数据失败
redis-check-rdb是redis提供的rdb文件检查工具
- RDB是一个紧凑压缩的二进制文件,代表redis在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如每6个小时执行bgsave备份,并把RDB文件复制到远端机器或者文件系统中用于灾备
- redis加载RDB恢复数据远远快于AOF的方式;RDB使用二进制的方式组织数据,直接把数据读取到内存中,按照字节的格式取出来放到结构体/对象中即可,但AOF是使用文本的方式来组织数据,则需要进行一系列的字符串切分
- RDB方式数据每办法走到实时持久化/秒级持久化,bgsave每次运行都需要执行fork创建子进程,属于重量级操作,频繁执行成本过高
- RDB文件使用特定二进制格式保存,redis版本演进过程有多个RDB版本,兼容可能有风险;可以通过写一个程序,直接遍历旧的redis中的所有key,把数据取出来插入到新的redis服务器中
AOF
redis的AOF(Append Only File)机制是一种持久化机制,用于将redis服务器接收到的所有写操作命令以追加的方式写入到磁盘中的日志文件中,重启时再重新执行AOF文件中的命令达到恢复数据的目的。
AOF的主要作用是解决数据持久化的实时性
开启AOF功能需要设置配置:appendonly yes,AOF文件名通过appendfilename配置,所在目录和RDB一样(/var/lib/redis)
所有的写入命令会追加到aof_buf(缓冲区)中,AOF缓冲区根据对应的策略向硬盘做同步操作,随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩目的,当redis服务器启动时,可以加载AOF文件进行数据恢复
redis执行命令速度快的重要原因,是直接操作内存;现在引入AOF后,又要写内存,又要写硬盘还可以想之前一样快吗?实际上,并没有影响到redis处理请求的速度,有以下两个原因:
- AOF机制并非是直接让工作线程把数据写入硬盘,而是先写入一个内存中的缓冲区,先积累一部分,再统一写入硬盘;这样大大降低了写硬盘的次数
- 硬盘上读写数据,顺序读写的速度是比较快的(比内存还是慢很多),AOF是每次把新的操作写入到原有文件的末尾,属于顺序写入
但缓冲区的数据还是在内存中,如果redis服务器突然挂了,缓冲区的数据就丢了。
redis给出一些选项,让我们选择缓冲区的刷新策略
刷新频率越高,性能影响就越大,数据可靠性就越高
刷新评率越低,性能影响就越小,数据可靠性就越低
系统调用write 和 fsync说明:
- write操作会触发延迟写(delayed write)机制,linux在内核提供页缓冲区用来提高硬盘IO性能,write操作在写入系统缓冲区后立即返回,同步硬盘操作依赖于系统调度机制;如:缓冲区页空间写满或到达特定时间周期。同步文件之前,如果此时系统故障宕机,缓冲区内数据丢失
- fsync针对单个文件操作,做强制硬盘同步,fsync将阻塞直到数据写入到硬盘
- 配置为always时,每次写入都要同步AOF文件,性能很差,在一般的SATA硬盘上,只能支持大约几百TPS写入。
- 配置为no时,由于操作系统同步策略不可控,虽然提供了性能,但数据丢失风险大大提高
- 配置everysec,是默认配置,兼顾数据安全和性能。理论上最多丢失1秒的数据
AOF文件持续增长,体积越来越大,会影响到redis下次启动的启动时间;redis启动的时候要读取aof文件内容(记录中间过程),而这个AOF文件有一些内容是多余的。
类似上述操作,实际上AOF只需要记录 set key 5即可。
因此redis就存在一个机制,能够针对AOF文件进行整理操作;也就是能够删除多余的内容,使AOF文件大小变小
AOF重写过程可以分为手动触发和自动触发
手动触发:调用bgrewriteaof命令
自动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定自动触发时间
- auto-aof-rewrite-min-size:触发重写时AOF的最小文件大小
- auto-aof-rewrite-percentage:当前AOF占用大小相比上次重传写时增加的比例
执行AOF重新请求,如果当前进程正在执行AOF重写,请求不执行;如果当前进程正在执行bgsave操作,重新命令延迟到bgsave完成之后再执行
父进程执行fork创建子进程;
父进程继续响应其它命令,所有写入命令仍然写入AOF缓冲区并根据appendfsync策略同步到硬盘,保证旧AOF文件机制正确(重写过程中,如果redis服务器挂了,可以根据旧AOF文件恢复数据);子进程根据内存快照,将命令合并到新的AOF文件中;
子进程完成重写,新AOF文件写入后,子进程发送信号给父进程,父进程把AOF重写缓冲区内临时保存的命令追加到新的AOF文件中,用新AOF文件替换旧AOF文件
注意:
重写的时候,不关心AOF文件中原来都有什么,只关心内存中最终的数据状态,子进程只需要把内存中当前的数据,获取出来,以AOF格式写入到一个新的AOF文件中;内存中的数据状态,就已经相当于把旧AOF文件结果整理后的样子;
RDB对于fork之后的新数据,就直接置之不理;AOF则对于fork之后的新数据,采用aof_rewrite_buf缓冲区的方式来处理;这是因为RDB本身的设计理念就是用来"定期备份"的,AOF的设计理念是"实时备份"
AOF本来是按照文本的方式写入文件的,但文本的方式写入文件,后续加载成本比较高;redis就引入了"混合持久化"的方式,结合了RDB和AOF的特点
按照AOF的方式,把每一个请求/操作,都记录文件,在触发AOF重写之后,把当前内存的状态按照RDB的二进制格式写入到新的AOF文件中,后续再进行的操作,仍然按照AOF文本的方式追加到文件后面
该选项为 yes 表示开启混合持久化
当redis上同时存在AOF文件和RDB快照时,启动redis以谁为主?以AOF为主,RDB直接被忽略了,AOF中包含的数据比RDB更全。
总结
以上就是我的redis学习笔记