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

Redis 的大 Key 对持久化的影响

Redis 的持久化方式有两种:AOF 日志和 RDB 快照。

文章目录

      • 1.AOF日志的影响
      • 2.对AOF重写和RDB的影响
      • 3.总结
      • 4.如何避免大 Key

1.AOF日志的影响

Redis 提供了 3 种 AOF 日志写回硬盘的策略

  1. Always,这个单词的意思是「总是」,所以它的意思是每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘;
  2. Everysec,这个单词的意思是「每秒」,所以它的意思是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘;
  3. No,意味着不由 Redis 控制写回硬盘的时机,转交给操作系统控制写回的时机,也就是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,再由操作系统决定何时将缓冲区内容写回硬盘。

这三种策略用于控制 fsync() 函数的调用时机。

在这里插入图片描述

  1. Always 策略就是每次写入 AOF 文件数据后,就执行 fsync() 函数;
  2. Everysec 策略就会创建一个异步任务来执行 fsync() 函数;
  3. No 策略就是永不执行 fsync() 函数;

大Key对Aof的影响:

  • 当使用 Always 策略的时候,如果写入是一个大 Key,主线程在执行 fsync() 函数的时候,阻塞的时间会比较久,因为当写入的数据量很大的时候,数据同步到硬盘这个过程是很耗时的。

  • 当使用 Everysec 策略的时候,由于是异步执行 fsync() 函数,所以大 Key 持久化的过程(数据同步磁盘)不会影响主线程。

  • 当使用 No 策略的时候,由于永不执行 fsync() 函数,所以大 Key 持久化的过程不会影响主线程。

2.对AOF重写和RDB的影响

当 AOF 日志写入了很多的大 Key,AOF 日志文件的大小会很大,那么很快就会触发 AOF 重写机制。

AOF 重写机制和 RDB 快照(bgsave 命令)的过程,都会分别通过 fork() 函数创建一个子进程来处理任务。

在创建子进程的过程中,操作系统会把父进程的「页表」复制一份给子进程,这个页表记录着虚拟地址和物理地址映射关系,而不会复制物理内存,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。

在这里插入图片描述

这样一来,子进程就共享了父进程的物理内存数据了,这样能够节约物理内存资源,页表对应的页表项的属性会标记该物理内存的权限为只读

随着 Redis 存在越来越多的大 Key,那么 Redis 就会占用很多内存,对应的页表就会越大。

  1. 在通过 fork() 函数创建子进程的时候,虽然不会复制父进程的物理内存,但是内核会把父进程的页表复制一份给子进程,如果页表很大,那么这个复制过程是会很耗时的,那么在执行 fork 函数的时候就会发生阻塞现象

  2. fork 函数是由 Redis 主线程调用的,如果 fork 函数发生阻塞,那么意味着就会阻塞 Redis 主线程。由于 Redis 执行命令是在主线程处理的,所以当 Redis 主线程发生阻塞,就无法处理后续客户端发来的命令

如果 fork 耗时很大,比如超过1秒,则需要做出优化调整:

  1. 单个实例的内存占用控制在 10 GB 以下,这样 fork 函数就能很快返回。
  2. 如果 Redis 只是当作纯缓存使用,不关心 Redis 数据安全性问题,可以考虑关闭 AOF 和 AOF 重写,这样就不会调用 fork 函数了。
  3. 在主从架构中,要适当调大 repl-backlog-size,避免因为 repl_backlog_buffer 不够大,导致主节点频繁地使用全量同步的方式,全量同步的时候,是会创建 RDB 文件的,也就是会调用 fork 函数。

写时复制: 当父进程或者子进程在向共享内存发起写操作时,CPU 就会触发缺页中断,这个缺页中断是由于违反权限导致的,然后操作系统会在「缺页异常处理函数」里进行物理内存的复制,并重新设置其内存映射关系,将父子进程的内存读写权限设置为可读写,最后才会对内存进行写操作。

在这里插入图片描述

在发生写操作的时候,操作系统才会去复制物理内存,这样是为了防止 fork 创建子进程时,由于物理内存数据的复制时间过长而导致父进程长时间阻塞的问题。

如果创建完子进程后,父进程对共享内存中的大 Key 进行了修改,那么内核就会发生写时复制,会把物理内存复制一份,由于大 Key 占用的物理内存是比较大的,那么在复制物理内存这一过程中,也是比较耗时的,于是父进程(主线程)就会发生阻塞。

两个阶段会导致阻塞父进程:

  1. 创建子进程的途中,由于要复制父进程的页表等数据结构,阻塞的时间跟页表的大小有关,页表越大,阻塞的时间也越长;
  2. 创建完子进程后,如果子进程或者父进程修改了共享数据,就会发生写时复制,这期间会拷贝物理内存,如果内存越大,自然阻塞的时间也越长;

3.总结

当 AOF 写回策略配置了 Always 策略,如果写入是一个大 Key,主线程在执行 fsync() 函数的时候,阻塞的时间会比较久,因为当写入的数据量很大的时候,数据同步到硬盘这个过程是很耗时的。

AOF 重写机制和 RDB 快照(bgsave 命令)的过程,都会分别通过 fork() 函数创建一个子进程来处理任务。会有两个阶段会导致阻塞父进程(主线程):

  1. 创建子进程的途中,由于要复制父进程的页表等数据结构,阻塞的时间跟页表的大小有关,页表越大,阻塞的时间也越长;
  2. 创建完子进程后,如果父进程修改了共享数据中的大 Key,就会发生写时复制,这期间会拷贝物理内存,由于大 Key 占用的物理内存会很大,那么在复制物理内存这一过程,就会比较耗时,所以有可能会阻塞父进程。

大 key 除了会影响持久化之外,还会有以下的影响。

  1. 客户端超时阻塞。由于 Redis 执行命令是单线程处理,然后在操作大 key 时会比较耗时,那么就会阻塞 Redis,从客户端这一视角看,就是很久很久都没有响应。

  2. 引发网络阻塞。每次获取大 key 产生的网络流量较大,如果一个 key 的大小是 1 MB,每秒访问量为 1000,那么每秒会产生 1000MB 的流量,这对于普通千兆网卡的服务器来说是灾难性的。

  3. 阻塞工作线程。如果使用 del 删除大 key 时,会阻塞工作线程,这样就没办法处理后续的命令。

  4. 内存分布不均。集群模型在 slot 分片均匀情况下,会出现数据和查询倾斜情况,部分有大 key 的 Redis 节点占用内存多,QPS 也会比较大。

4.如何避免大 Key

  1. 设计阶段,就把大 key 拆分成一个一个小 key。
  2. 定时检查 Redis 是否存在大 key ,如果该大 key 是可以删除的,不要使用 DEL 命令删除,因为该命令删除过程会阻塞主线程,而是用 unlink 命令(Redis 4.0+)删除大 key,因为该命令的删除过程是异步的,不会阻塞主线程。

相关文章:

  • AOP 面向切面编程
  • Python-爬虫、自动化(selenium,动态网页翻页,模拟搜索,下拉列表选择、selenium行为链)
  • 关联规则代码实现
  • Redis 键(key)相关操作和常用命令
  • 大模型系统和应用——Prompt-learning Delta Tuning
  • Python自动化小技巧07——符号计算求方程解、二重积分
  • js获取本周的周一、周日和上周的周一、周日
  • 基于Php幼儿园管理系统
  • 基于Spring Boot+MySQL的半自动标注系统(人、车、人脸的自动检测)设计与实现
  • 置顶汇总:OpenGL图形学、Shader进阶、Android-RTC视频处理、学术讨论群。
  • SpringBoot项目配置postgresql数据库(配置多数据源)
  • idea分析栈帧链
  • IAR9.30以上版本安装、注册、新建工程和配置过程详细介绍
  • UML测试题(用例图基础b)
  • kvm虚拟机基本管理和网络管理
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • Docker: 容器互访的三种方式
  • gulp 教程
  • JavaScript类型识别
  • JAVA并发编程--1.基础概念
  • k个最大的数及变种小结
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • maven工程打包jar以及java jar命令的classpath使用
  • PHP的Ev教程三(Periodic watcher)
  • Python学习笔记 字符串拼接
  • React 快速上手 - 07 前端路由 react-router
  • TypeScript实现数据结构(一)栈,队列,链表
  • 力扣(LeetCode)21
  • 聊聊flink的BlobWriter
  • 聊聊flink的TableFactory
  • 前端技术周刊 2019-02-11 Serverless
  • 让你的分享飞起来——极光推出社会化分享组件
  • 算法系列——算法入门之递归分而治之思想的实现
  • 一天一个设计模式之JS实现——适配器模式
  • 原生js练习题---第五课
  • 白色的风信子
  • 容器镜像
  • 数据可视化之下发图实践
  • ​Spring Boot 分片上传文件
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • #AngularJS#$sce.trustAsResourceUrl
  • #define 用法
  • #ifdef 的技巧用法
  • $.each()与$(selector).each()
  • (1)Nginx简介和安装教程
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (solr系列:一)使用tomcat部署solr服务
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (待修改)PyG安装步骤
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (原創) 如何將struct塞進vector? (C/C++) (STL)