您的位置:首页 > 游戏 > 手游 > Redis高级-----持久化AOF、RDB原理

Redis高级-----持久化AOF、RDB原理

2024/10/6 14:36:16 来源:https://blog.csdn.net/m0_73171073/article/details/141857449  浏览:    关键词:Redis高级-----持久化AOF、RDB原理

目前已更新系列:

当前:Redis高级-----持久化AOF、RDB原理

Redis高级---面试总结5种数据结构的底层实现

Redis高级----主从、哨兵、分片、脑裂原理-CSDN博客

Redis高级---面试总结内存过期策略及其淘汰策略

计算机网络--面试知识总结一

计算机网络-----面试知识总结二

计算机网络--面试总结三(Http与Https)

计算机网络--面试总结四(HTTP、RPC、WebSocket、SSE)-CSDN博客

知识积累之ThreadLocal---InheritableThreadLocal总结

并发编程之----线程池ThreadPoolExecutor,Excutors的使用及其工作原理

AOF

AOF配置

AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF:

# 是否开启AOF功能,默认是no
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"

AOF的命令记录的频率也可以通过redis.conf文件来配:

# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always 
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec 
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no

刷盘策略:

aof来持久化数据是通过追加命令的方式实现的,即会记录对数据库修改的命令,如果数据库宕机了,试用aof来恢复数据,只需要将aof中的命令执行一边就可以了,aof提供了三种刷盘策略

首先对于每一个更新命令,都会先将数据存入aof缓冲区中(用户空间),然后通过系统调用将数据复制到内核缓冲区中,

  • always:每次执行更新命令都立刻将数据从aof缓冲区立刻刷盘道aof磁盘文件中
  • erverysec:每秒执行刷盘,即每隔一秒就将数据刷盘道aof文件中
  • no:不执行刷盘任务,而是将刷盘任务交给操作系统由操作系统决定什么时候将数据刷入aof文件

其中always方式进行刷盘的时候是以同步的方式进行的执行fsync()进行刷盘

而试用everysec则是采用异步的方式执行fsync()方式进行刷盘

三种策略对比:

AOF重写机制原理

因为aof是通过追加命令的方式进行持久化的,这会使得aof文件非常大,所以为了优化这个问题,有了aof重写机制,即通过aof重写将aof文件中只保留每个key的最新数据,我们可以到配置文件中配置一个重写阈值比如64MB,即当aof大小超错64mb时执行重写策略,策略如下:

  • 首先会fork一个子进程bgrewriteof,然后对于子进程就有了父进程的页表数据,即映射同一片无力内存空间,并且对于这片空间都是只读权限,然后子进程就开始读取每个数据库中的数据,并且将数据以命令的形式存入aof文件中
  • 然后如果此时主进程收到对数据的修改操作,那么主进程会做如下几件事:
    • 执行客服端的命令对数据进行修改操作
    • 执行写时复制操作,即将访问到的key的物理内存数据拷贝到新的内存中
    • 记录该数据到aof缓冲区中
    • 记录该数据到aof重写缓冲区中(至于为什么看下面,主要就是数据一致性问题)
  • 当子进程对数据重写完成之后会想主进程放松一个信号量去通知已经重写完毕,
  • 然后朱进程接收到之后就会将此时aof缓冲区中之前由于在拷贝之间修改的数据同步刷入到新的aof文件中,这样就可以让新老两个aof文件数据保持一致,然后覆盖原来的aof文件

重上面重写aof来看,整个过程中需要阻塞主进程的过程如下:

  • 首先fork子进程需要阻塞
  • 其次发生了写时复制时会阻塞,因为需要将原来的物理内存数据拷贝,如果这个key较大,那么可能导致阻塞时间较长
  • 子进程在生成了新的aof文件后通知主进程,然后朱进程将aof缓冲区的数据刷到新的aof的,然后将新的aof覆盖旧的aof文件的过程

RDB

RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。快照文件称为RDB文件,默认是保存在当前运行目录。

执行时机

RDB持久化在四种情况下会执行:

  • 执行save命令
  • 执行bgsave命令
  • Redis停机时
  • 触发RDB条件时

1)save命令

执行下面的命令,可以立即执行一次RDB:

save命令会导致主进程执行RDB,这个过程中其它所有命令都会被阻塞。只有在数据迁移时可能用到。

2)bgsave命令

下面的命令可以异步执行RDB:

这个命令执行后会开启独立进程完成RDB,主进程可以持续处理用户请求,不受影响。

3)停机时

Redis停机时会执行一次save命令,实现RDB持久化。

4)触发RDB条件

Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:

# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
save 900 1  
save 300 10  
save 60 10000

RDB的其它配置也可以在redis.conf文件中设置:

# 是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱
rdbcompression yes# RDB文件名称
dbfilename dump.rdb  # 文件保存的路径目录
dir ./

RDB原理

bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件。

fork采用的是copy-on-write技术:

  • 当主进程执行读操作时,访问共享内存;
  • 当主进程执行写操作时,则会拷贝一份数据,执行写操作。

bgsave快照过程中,如果主线程修改了共享数据,发生了写时复制后,rdb快照保存的是原本的内存数据,而主线程刚修改的数据,是没办法在这一时间写入rdb文件的,只能交由下一次的bgsave快照。
所以redis在使用bgsave快照过程中,如果主线程修改了内存数据,不管是共享的内存数据,rdb
快照都无法写入主线程刚修改的数据,因为此时主线程(父进程)的内存数据和子进程的内存数据已经分
离了,子进程写入到rdb文件的内存数据只能是原本的内存数据。如果系统恰好在rdb快照文件创建完毕后崩溃了,那么redis将会丢失主线程在快照期间修改的数据。
 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com