文章目录
- 一、什么是持久化
- 二.RDB持久化
- 1. 什么是RDB持久化
- 2. RDB持久化的触发条件
- 1)RDB生成快照的原理
- 2) 自动触发
- 三.AOF持久化
- 1.AOF的工作流程
- 2.AOF文件的同步策略
- 3.AOF重写
- 四.混合持久化
一、什么是持久化
- 持久化就是指把内存的数据存储在硬盘上,使重启进程/重启主机后,数据仍然存在;
- Redis是一个内存数据库,但内存是断电易失的,即内存中的数据不是持久的,因此,Redis需要将数据进行持久化,即将数据保存到硬盘上;
- Redis既会在内存中存数据,也会在硬盘上存数据;这两份数据是否存在差异,关键在于持久化的策略;
- 当插入一个数据时,Redis会同时将数据写入内存和硬盘;当查询某数据时,直接从内存中取;硬盘的数据只是在Redis服务器重启时,用来恢复内存中的数据;
Redis实现持久化的方式共三种:
- RDB持久化,即定期备份;
- AOF持久化,即实时备份
- 混合持久化,即同时采用如上两者
二.RDB持久化
1. 什么是RDB持久化
RDB持久化即定期备份,RDB会定期根据内存中存的数据来生成一个二进制快照文件(dump.rdb),并将其保存的磁盘上;
RDB快照:
- 快照就是对"某个时刻"内存中数据的记录,会将记录的数据写入到磁盘的某个文件上;
2. RDB持久化的触发条件
- 手动触发:save或者bgsave
- save: 生成快照时,会阻塞客户端的其他命令,因此不建议使用,相当于"前台进程";
- bgsave: 生成快照时,不会阻塞客户端命令,相当于"后台进程";
- 自动触发: 1.配置文件配置触发时机 2.从节点进行全量复制 3.执行shutdown
1)RDB生成快照的原理
- 这里的快照生成特指bgsave的原理;
- RDB快照的生成主要依靠:多进程和写时拷贝;
- 当相应生成快照时,首先判断当前是否有其他子进程正在生成快照,如果有就直接返回
- 如果没有,就fork出一个子进程;
- fork后,父子进程会共享内存数据,此时并不会立即复制数据;后续,如果子进程和父进程的数据是一致的,就不会发生修改;一旦父进程的数据要被修改,子进程才会真正触发拷贝;
- 整个过程中,子进程负责写文件,生成快照过程,父进程继续接收客户端请求,提供服务;
- 子进程完成持久化后,通知父进程,父进程更新统计信息就销毁子进程;
问题一: 如何理解fork对父进程的复制(理论上的方案)?
- fork产生的子进程是对父进程的复制
- 所谓的复制就是将其内容都完整的拷贝,与父进程的区别只是在空间独立,但内容均一样,这就意味着指针的指向也会相同,即如果是文件操作,那么其写入的文件也和父进程一样;
- 故对子进程的持久化,就相当于把父进程本体的数据进行持久化
问题二: fork进行拷贝是否会消耗大量时间,造成效率损失(实际上的方案)?
- fork进行拷贝时并不是无脑的直接拷贝,而是一种"写时拷贝"
- 如果子进程的数据和父进程的数据一致的,那么就不会真正拷贝(共用一份数据);
- 如果一方的数据要发生修改了,那么子进程会在修改前完成对应的数据拷贝;
- 在bgsave中,绝大多数的内存数据是不需要修改的,因此"写时拷贝"并不会触发多次,也就保证了高效性;
2) 自动触发
redis生成的快照为.rdb文件,放在redis的工作目录中,其可以在redis.conf配置文件进行配置;
该rdb文件是一个二进制文件,redis默认开启RDB;
- 二进制文件是将内存中的数据进行压缩保存的,虽然压缩会消耗一定cpu资源,但能节省存储空间
- 每次Redis服务器启动,都会读取该rdb文件,如果rdb文件的格式发生错误,那么Redis服务器就会启动失败;
redis提供了rdb文件的检查工具。
rdb持久化可以进行多次,当执行生成rdb镜像操作时,会先将快照数据先保存在临时文件中,当快照生成后,删除之前的rdb文件,将生成的rdb文件改名为刚才的dump.rdb文件;
- 虽然时间可以自由配置,但生成一次rdb快照的成本是比较高的,这个频率不能太频繁;
- 下一个rdb文件的生成和前一个rdb文件是存在间隔的,如果这个间隔期间进行了大量的key请求且此时服务器正好挂了,那么就会导致数据丢失;
- 除了上面的自动配置方式,如果是正常的服务器重启,那么其会通过shutdown命令关闭服务器,也会触发快照生成(因此重启时数据不会丢失,但如果服务器挂了,那么在重启数据就会丢失)
三.AOF持久化
- AOF持久化即实时备份,其会将用户的每个操作都记录在文件中,当redis重启时,就会读取该文件恢复数据;
- AOF文件和RDB文件不同,其是一个文本文件,而后者是二进制文件;
1.AOF的工作流程
- 所有的写入命令都会添加到AOF缓冲区中
- AOF缓冲区根据**同步策略(2)**向硬盘做同步操作
- 随着AOF文件的变大,定期对AOF文件进行重写(3),以进行数据压缩;
- 当重启Redis时,加载AOF进行数据恢复;
2.AOF文件的同步策略
- always: 每次写命令都会执行fsync,将数据立即刷盘;
- everysec: 每秒执行一次fsync;
- no:不主动执行fsync,由操作系统决定刷盘时间;
- 实际上,当写命令事件完成后,还需要将aof缓冲区的文件再写入到系统缓冲区中(调用write);
- fsync: 该函数功能为将系统缓冲区的数据刷到磁盘上;
3.AOF重写
AOF文件会记录用户的操作,当其大到一定程度,如果不对其体积做出调整,势必会影响启动时间;
因此,Redis引入了重写机制,能对AOF文件进行整理,剔除或合并其中的冗余操作,达到瘦身效果;
AOF重写流程:
- 当触发 AOF 重写时,Redis 会 fork 出一个子进程,由子进程负责重写 AOF 文件。
- 父进程会维护一个重写缓冲区,重写AOF期间,每次执行完一个写命令,会同时将命令写入到AOF缓冲区和重写缓冲区;
- 子进程重写完成后,通知父进程,父进程将重写缓冲区的数据写入到新的AOF文件中,之后用新的AOF文件替换旧的;
- 为什么父进程会同时写AOF缓冲区和重写缓冲区?
- 重写时,如果服务器挂了,子进程内存就会消失;新AOF文件就不完整,因此这样保证数据完整性;- 子进程重写时,不会读取原AOF文件的内容,而是扫描当前数据库数据,将键值对转换成指令,将指令写入到重写日志中;
- 子进程进行写数据时,实际是写的新的AOF文件;
- 如果执行重写时,正在生产快照,则重写阻塞;
- 使用bgrewriteof进行重写;
- 引入AOF后,既要写内存,还有写硬盘,redis的速度不会受到影响吗?
- 不会,AOF并非直接将数据写入到硬盘,而是先写入到内存的一个缓冲区,积累一定数目,才进行写入;- AOF是先将操作写入到缓冲区,但缓冲区也是内存,万一此时掉电了怎么办,那数据不就丢了吗?
- 是的,没来得及写入就会丢失数据,并不能追求效率的同时还追求安全;
四.混合持久化
- AOF是按照文本的方式进行写入的,但这样的方式使得后续进行加载时,成本是比较高的;
- Redis引入了混合持久化的方式,结合了AOF和RDB的优点;
- 按照AOF的方式,将每个请求/操作,都记录到文件中,触发AOF重写后,把当前内存的状态按照rdb二进制格式写入到新的aof文件中,后续再进行操作,仍然按照AOF文本的方式追加到后边