大key对持久化的影响

大 Key 对 AOF 日志的影响

AOF 日志三种写回磁盘的策略:

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

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

在这里插入图片描述

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

分别说说这三种策略,在持久化大 Key 的时候,会影响什么?

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

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

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

大 Key 对 AOF 重写和 RDB 的影响

AOF日志写入了很多的大 Key·AOF 日志文件的大小会很大,那么很快就会触发 AOF 重写机制。AOF 重写机制RDB 快照的过程,都会分别通过fork()函数创建一个子进程来处理任务。

页表复制,内存共享

在创建子进程的过程中,操作系统会把父进程的页表复制一份给子进程,这个页表记录着虚拟地址和物理地址映射关系,而不会复制物理内存,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个子进程就共享了父进程的物理内存数据了,这样能够节约物理内存资源。在通过fork()函数创建子进程的时候,虽然不会复制父进程的物理内存,但是内核会把父进程的页表复制一份给子进程,如果页表很大,那么这个复制过程是会很耗时的,那么在执行fork函数的时候就会发生阻塞现象。

执行info命令获取到latest_fork_usec指标,表示 Redis 最近一次 fork 操作耗时。

latest_fork_usec:100

fork 耗时很大,则需要做出优化调整:

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

物理内存的复制

当父进程或者子进程在向共享内存发起写操作时,操作系统会在进行物理内存的复制,并重新设置其内存映射关系。这个过程被称为写时复制Copy On Write

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

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

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

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

在这里插入图片描述

总结

  • 当 AOF 写回策略配置了 Always 策略,如果写入是一个大 Key,主线程在执行 fsync() 函数的时候,阻塞的时间会比较久。
  • AOF 重写机制RDB 快照的过程,都会分别通过fork()函数创建一个子进程来处理任务。会有两个阶段会导致阻塞父进程:
  • 创建子进程的途中,由于要复制父进程的页表等数据结构,页表越大,阻塞的时间也越长;
  • 创建完子进程后,如果父进程修改了共享数据中的大 Key,就会发生写时复制,这期间会拷贝物理内存,由于·大 Key ·占用的物理内存会很大。

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

  • 客户端超时阻塞。由于 Redis 执行命令是单线程处理,然后在操作大 key 时会比较耗时,那么就会阻塞 Redis,从客户端这一视角看,就是很久很久都没有响应。
  • 引发网络阻塞。每次获取大 key 产生的网络流量较大,如果一个 key 的大小是 1 MB,每秒访问量为 1000,那么每秒会产生1000MB的流量,这对于普通千兆网卡的服务器来说是灾难性的。
  • 阻塞工作线程。如果使用del删除大 key 时,会阻塞工作线程,这样就没办法处理后续的命令。
  • 内存分布不均。集群模型在slot分片均匀情况下,会出现数据和查询倾斜情况,部分有大 key 的 Redis 节点占用内存多,QPS 也会比较大。

如何避免大 Key 呢?

  • 最好在设计阶段,就把大 key 拆分成一个一个小 key。
  • 定时检查 Redis 是否存在大 key ,如果该大 key 是可以删除的,不要使用DEL 命令删除,因为该命令删除过程会阻塞主线程,而是用unlink命令(Redis 4.0+)删除大 key,因为该命令的删除过程是异步的,不会阻塞主线程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值