对于redis持久化的一些思考

对于redis持久化的一些思考

前言

去了一趟上海,感概不愧是大城市,连快递都用上缓存了。

在这里插入图片描述

AOF

redis 作为内存数据库,利用内存读写速度快来提高系统的性能。那么暂存在内存中的数据,必然存在丢失的风险,redis 给出了两种解决方案。AOF(Append Only File) 持久化功能的工作流程如下

在这里插入图片描述
Q:为什么要先执行写命令,再记录操作日志?
我的理解是,如果先记录操作日志,那就需要做 redis 指令的语法校验,会耗费时间和性能。如果不做校验,那么在 redis 从 aof 文件恢复时,会重复执行语法错误的指令,这是没有必要的无效操作。
Q:AOF文件内容是什么样的?
以set city xiamen 为例

*3
$3
set
$4
city
$6
xiamen

*代表是 aof 格式的文件,*3代表这个指令有三个部分,$后跟的就是指令的长度了。

从上图就可以发现 redis 可能存在丢数据的节点了。比如主进程刚执行完写命令,还没记录日志就宕机了。也能发现 redis 的性能瓶颈会发生在硬盘上,假如硬盘的 I/O 负荷较大,那么记录操作日志的同步操作就会阻塞到下一个 redis 指令的执行。

当然记录操作日志也没那么简单,具体流程如下
在这里插入图片描述
redis 提供的三种回写策略针对的是写入内核缓冲区后,何时写入硬盘。三种策略位 Always、Everysec、No,无非就是对于性能和数据丢失率的取舍,这里不细说。深究一下源码来分析这三种策略到底有什么不同。其实区别就在于这三种策略调用**fsync()**的时机。

Always:每次写入 aof文件数据后,就执行 fsync() 函数
Everysec:会创建一个异步任务来执行 fsync() 函数
No:永不执行 fsync() 函数,交给操作系统来决定何时调用

AOF重写

当 redis 重启时,如果从 aof 文件恢复的话,就需要把文件中的所有指令都执行一次,那么如果文件太大的话必然会影响恢复的速度,并且可能会存在无效的操作指令,比如同个 key 操作了多次,那么只需要执行最后一次即可。所以 AOF 的重写必然会去合并相同 key 的操作指令。那么当主进程 fork 生成 bgrewriteaof 子进程去执行 AOF 重写时会发生什么呢?
在这里插入图片描述
主进程在通过 fork 系统调用生成 bgrewriteaof 子进程时,操作系统会把主进程的页表复制一份给子进程,这个页表记录着虚拟地址和物理地址映射关系,而不会复制物理内存,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。

Q:如果此时对父进程内存中的数据进行修改,会发生什么?
创建 bgrewriteaof 子进程之后,redis 会设置一个 AOF 重写缓冲区,在重写期间,父进程发生写操作时,会同时向 AOF 缓冲区和 AOF 重写缓冲区进行输出。当 bgrewriteaof 子进程扫描完所有数据,逐一把内存数据的键值对转换成一条命令,再将命令记录到重写日志后,会将 AOF 重写缓冲区的数据也写入到 AOF 重写文件中,最后在将重写后的 aof 文件覆盖原来的 aof 文件。

RDB

redis 提供了两种指令来生成 rdb 文件。分别是 save 和 bgsave,这两者的区别在于是否在主线程进行快照的记录。因为 RDB 是做全量的快照,如果用 bgsave 进行 RDB 快照的话,在创建子进程的时候,会因为复制太大的页表而导致 redis 阻塞在fork() 函数,主线程无法继续执行,相当于停顿了。所以当 rdb 文件太大时,建议使用 save 的方式。

Q:执行快照时,数据能被修改吗?
在这里插入图片描述
能。当内存数据发生修改时会触发写时复制(Copy-On-Write),所以子进程读到的还是修改前的内存数据。这样也会引发一些问题。比如,修改的数据在父子进程中值不同,这种情况就只能等待下次 bgsave 时才能将最新的数据记录到 rdb 文件中,当然如果在触发下次 RDB 之前就宕机了,那么最新的修改值就丢失了。如果生产环境采用 RDB 的持久化方式的话,需要注意一点,如果所有的共享内存都被修改,则此时的内存占用是原先的两倍。所以,针对写操作多的场景,我们要留意下快照过程中内存的变化,防止内存被占满了。

总结

AOF 和 RDB 都是在平衡性能和数据丢失率的问题,两者都有优点和缺点,所以就有了 RDB 和 AOF 的合体混合持久化。这个方法是在 Redis4. 0提出的。当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 aof 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 aof 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 aof 文件替换旧的的 aof 文件。也就是说,使用了混合持久化,aof 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值