当前位置: 首页 > news >正文

Redis——持久化

AOF日志

概述:

AOF日志用于记录写操作命令,在redis重启后通过逐步执行写命令实现内存的数据再现

*3表示当前命令有三个部分,$+数字表示这部分命令、键或值包含多少字节。

执行顺序:先执行写操作再进行日志记录

优点:
  • 避免额外检查开销:执行后可保证名类都是正确的,无需额外检查直接写入即可。
  • 不会阻塞当前写操作执行:只有当写操作执行成功后才记录到日志里。
缺点:
  • 崩溃时数据丢失:记录日志前意外宕机,数据有丢失风险。
  • 阻塞后续命令执行:记录日志是磁盘IO操作,可能会阻塞下一条命令。

日志记录过程:

与MySQL类似,AOF日志先记录到Redis的内存中再通过write操作写入内核的页缓冲区最后由内核选择合适的时机写入到磁盘中

 三种写回策略:

  • Always:每次写操作命令执行完后,都直接刷盘AOF
  • Everysec:每次写操作命令执行完后,先写入到AOF文件的内核缓冲区,每隔一秒刷盘
  • No:每次写操作命令执行完后,先写入到内核缓存区,再由操作系统决定什么时候刷盘

这三种策略都无法完美解决主线程阻塞数据丢失,且这些策略实际上是控制fsync方法的调用时机(参考MySQL)

  • 高性能采用No(永不执行fsync)
  • 高可靠采用Always(每次都调用fsync)
  • 折中采用Everysec。

AOF重写机制

AOF日志存储在文件中,随着执行的写操作命令越来越多文件会越来越大,进而导致恢复内存数据的性能变差,所以Redis设定了一个阈值,当AOF日志大小超过阈值后会启用AOF重写机制来压缩日志。

行为:

AOF重写实质是读取当前数据库的所有键值对,转化为对应的命令记录到新的AOF文件中,全部记录完成后替换原有的AOF日志(这样即使重写失败也不会影响原日志)

特点:

AOF重写相当于只记录最新命令,过滤了原日志中key的历史命令和删除key的命令,从而无需复现键值对的多次修改过程,并达到压缩效果

AOF后台重写

重写日志是比较耗时的,不应该由主进程进行,所以Redis使用了后台子进程bgrewriteaof来完成

  • 子进程重写期间主进程可以继续处理请求,避免堵塞
  • 子进程重写可触发写时复制:子进程和主进程可直接共享内存数据,但若其中一方修改了共享内存,就会为对应进程生成独立的数据副本以供修改。
  • 如果使用线程多线程之间会共享内存且修改操作是直接影响内存的,不会生成数据副本,需要加锁来控制,性能较低
初始状态—共享物理内存
  • 主进程通过fork调用子进程时,操作系统会把主进程的页表复制一份给子进程页表条目指向相同的物理内存页,且这些物理内存页会标记为只读
  • 这样二者不同的虚拟内存空间就会指向同一个物理内存,从而大幅节约了物理内存资源避免创建子进程时就复制一份独立的物理内存导致主进程阻塞
写操作触发—物理内存分离
  • 页错误触发:当其中一个进程进行写操作时,CPU检测到只读权限冲突,触发页错误。
  • 分配新物理内存页内核为修改的进程分配新的物理内存页(局部物理内存)复制原页的内容到新页,并更新页表的对应条目使其指向新页(标记为可写)
  • 页表独立更新:修改进程的页表指向了新物理内存页,更新只会发生在新页中父子进程的页表映射完全独立

主进程进行了修改操作后,子进程记录的AOF日志与主进程的实际命令不一致

解决数据不一致:

Redis设置了一个AOF重写缓冲区,执行的写命令会同时追加到AOF缓冲区和AOF重写缓冲区

子进程完成重写操作后,会异步向主进程发送一条信号,主进程收到信号后调用处理函数

  • 将AOF重写缓冲区的所有内容追加到新的AOF文件中,使得新旧两个AOF文件数据库状态一致
  • 新的AOF文件改名,覆盖旧AOF文件
对主进程的阻塞时机:
  • 执行信号函数时,主进程是阻塞状态
  • 写时复制时,主进程是阻塞状态
  • 复制页表时,主进程是阻塞状态

RDB快照

概述:

AOF记录的是写操作命令,RDB记录的是二进制数据,也就是记录Redis某一个瞬间的实际内存数据。因此恢复数据时,RDB的效率要比AOF更高,因为不用再逐步执行命令,直接读取RDB文件即可

快照的使用:

  • save命令:主进程生成RDB文件,可能会阻塞主进程
  • bgsave命令:创建子进程生成RDB文件,避免阻塞主进程

save 900 1
save 300 10
save 60 10000
  • save指令默认执行的是bgsave,意思是900秒内对数据库进行了1次修改。就会执行bgsave快照。
  • RDB快照是全量快照(AOF是增量写入),所以执行快照是比较损耗性能的操作。我们通常选择至少5分钟才执行一次快照,但这样也会导致我们丢失更多数据

执行快照时是否可以修改?

与AOF重写一致,主线程是可以修改的,bgsave命令会通过fork调用子进程进行快照操作

  • 使用的依然是写时复制技术,但写时复制会导致父子进程数据不一致的问题。
  • 所以快照时的修改操作只能在下一次快照时生效,如果Redis恰好在快照文件完成后崩溃会丢失主进程在快照期间修改的数据
  • 极端情况下,若所有的共享内存都被修改,内存占用会是原来的两倍

混合持久化:

虽然RDB快照恢复比AOF快,但频率过低时丢失较多数据频率较高则会带来额外性能开销

所以Redis4.0后使用了混合持久化,混合lAOF日志与RDB快照

工作流程:

  • 在AOF重写日志时,子进程会将共享内存数据中的键值对以RDB的形式写入到AOF文件中
  • 主进程重写过程中修改的数据会进入AOF重写缓冲区中,缓冲区中的命令会以AOF形式写入到AOF文件中
  • 最后AOF文件前半部分是RDB类型的全量数据后半部分是AOF格式的增量数据

优点和劣势:

  • 重启时数据加载速度很快,且保存时数据丢失较少,兼备了AOF和RDB的优点
  • 但文件内部格式较为混乱,可读性差

大Key问题

对AOF日志三种写回策略的影响:

  • 对Always:主线程每次执行完命令都执行fsync都会阻塞较长时间
  • 对EverySec:异步线程执行fsync,不阻塞主线程
  • 对No:不执行fsync,不会阻塞主线程

对AOF重写和RDB快照影响:

AOF日志写入较多大Key后很快就会触发AOF重写重写和快照时会复制一份主进程的页表给子进程,若页表较大,复制过程会比较耗时,可能会造成主进程阻塞

如果在AOF重写或RDB快照过程中修改了大Key键值,则会触发写时复制,在物理内存中拷贝大Key数据副本,这个过程占用内存比较大,且比较耗时,可能会造成主进程阻塞

其他阻塞影响:

客户端超时阻塞:Redis单线程处理命令操作大Key比较耗时进而阻塞

网络阻塞:每次获取大Key产生的网络流量较大,在每秒访问量高时对服务器的压力极大

工作线程阻塞网络I/O大key时,会阻塞工作线程,无法处理其他任务

内存分布不均集群模式可能会出现数据和查询倾斜有大Key的Redis节点占用内存多

避免大key:

设计阶段将大key拆分成一个个小key

定时检测是否存在大key,如果可以删除则使用unlink命令异步删除,del会阻塞主线程

相关文章:

  • 单细胞转录组(1)
  • 嵌入式培训之数据结构学习(五)栈与队列
  • 手撕I2C和SPI协议实现
  • 机器学习回归预测中预处理的特征工程
  • 数据结构与算法——双向链表
  • QT调用Halcon查询所有摄像头名称
  • 基于 Python 的界面程序复现:标准干涉槽型设计计算及仿真
  • UE 材质基础 第一天
  • WPS JS宏实现去掉文档中的所有空行
  • 数组集合互转问题
  • 星火杯大模型应用创新赛学习笔记——datawhale
  • 深入探讨 Java 17的 Text Blocks
  • V型不锈钢对夹球阀:高性价比工业控制解决方案-耀圣
  • 布隆过滤器和布谷鸟过滤器
  • 关系代数和关系数据库语言(SQL)
  • 202537 |《代码整洁之道》笔记
  • C# 创建线程的方式
  • 基于LLM合成高质量情感数据,提升情感分类能力!!
  • 程序人生-Hello’s P2P
  • C语言| 指针变量的定义
  • “先增聘再离任”又添一例,景顺长城基金经理鲍无可官宣辞职
  • 北京韩美林艺术馆党支部书记郭莹病逝,终年40岁
  • 从近200件文物文献里,回望光华大学建校百年
  • 福州一宋代古墓被指沦为露天厕所,仓山区博物馆:已设置围挡
  • A股三大股指低收:汽车股领涨,大金融走弱,两市成交近1.1万亿元
  • “AD365特应性皮炎疾病教育项目”启动,助力提升认知与规范诊疗