小言_互联网的博客

对于redis持久化的一些思考

284人阅读  评论(0)

对于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 格式的增量数据。


转载:https://blog.csdn.net/weixin_43776741/article/details/127634855
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场