前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >redis AOF性能瓶颈分析

redis AOF性能瓶颈分析

作者头像
用户5166556
发布2023-03-18 14:45:11
8650
发布2023-03-18 14:45:11
举报

最近发现一个问题,redis在高流量写入的情况下,偶发性出现客户端延迟升高,经过排查发现redis AOF重写 fork 子进程导致。为什么要进行AOF重写,以及如何避免AOF重写呢?本文做个介绍。

1. 什么是AOF

AOF是redis防止数据丢失的日志备份策略,总共有三种方式

  • Always 同步写回:每个写命令执行完同步地将日志写回磁盘;可靠性高,数据基本不会丢失,但同时每次命令都需要写到磁盘,性能影响比较大。除非对于数据丢失非常敏感,否则不会选择这种策略。
  • Everysec 每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;首先异步写到缓冲区,redis会使用单独的线程每秒写回到磁盘,如果这期间出现宕机,可能会丢失1s左右的数据,但是性能得到了保证。相当于是性能和数据丢失之间做了一个折衷,这个也是默认策略。
  • No 操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。由操作系统控制何时写会,性能非常好;如果发生宕机,也会造成大量数据丢失。

说到AOF,其实很多人都会拿它跟Rdb去做比较,Rdb是以二进制的方式存储到磁盘上。体积更小,当出现服务重启或者宕机,相对于AOF恢复速度更快。

另外一点,RDB和AOF对客户端的写入性能影响,一般情况下,AOF的写入性能是比不上RDB的,因为AOF多了一个写入操作,但是随着写入数据量越来越大,这个差距会越来越小。看完本文后,你应该能够找到答案。具体可以参考redis官网https://redis.io/topics/persistence,这里不过多赘述。

2. AOF重写又是怎么回事

很多同学对redis的写AOF文件和AOF重写傻傻分不清,无论是发生时机或者操作对象其实是没有任何关系的。

2.1. 写AOF文件

写AOF文件发生在客户端请求redis server,这个时候就会产生一条AOF记录,这条记录何时写入磁盘跟自身设置的AOF策略控制相关,可以同步、也可以异步写入。

2.2. AOF重写操作

如果redis server接受的写请求越来越多,那么AOF文件会越来越大,为了防止AOF文件无限膨胀(打爆磁盘)以及不利于redis server 宕机后的恢复,所以要进行重写。其实说白了就是一个重复命令合并的过程。

对于上图几个关键点:

  • 1、在重写期间,由于主进程依然在响应命令,为了保证最终备份的完整性;因此它依然会写入旧的AOF file中,如果重写失败,能够保证数据不丢失。
  • 2、为了把重写期间响应的写入信息也写入到新的文件中,因此也会为子进程保留一个buf,防止新写的file丢失数据。如果主进程收到了写请求,子进程和父进程是通过管道的方式进行发送这个期间发生的请求,所以这个期间写操作并不会丢失。
  • 3、重写是直接把当前内存的数据生成对应命令,并不需要读取老的AOF文件,最后通过 rename 完成文件的替换工作。
2.3. AOF重写发生条件。
  • 1、开启AOF
  • 2、没有RDB和AOF进程运行
  • 3、auto-aof-rewrite-min-size:AOF 文件大小绝对值的最小值,默认为 64MB,具体见redis.conf。auto-aof-rewrite-percentage:AOF 文件大小超出基础大小的比例,默认值为 100%,即超出 1 倍大小。

如下是源码所示:

//如果AOF功能启用、没有RDB子进程和AOF重写子进程在执行、AOF文件大小比例设定了阈值,以及AOF文件大小绝对值超出了阈值,进一步判断AOF文件大小比例是否超出阈值
if (server.aof_state == AOF_ON && 
server.rdb_child_pid == -1 &&
server.aof_child_pid == -1 && 
server.aof_rewrite_perc 
&& server.aof_current_size > server.aof_rewrite_min_size) 
{.....}

看到这里,再想想,为什么redis之所以添加各种条件限制AOF的发生?

尽可能减少CPU和IO消耗

3. 如何避免AOF造成的影响

3.1. 影响原因

上文中也说了,AOF主要耗时发生在fork一个子进程并且会阻塞主进程,这是为什么呢?

因为fork子进程时,子进程是会拷贝父进程的页表,即虚实映射关系,但是fork不会把所有的内存数据都copy到子进程,只会copy一部分有用的数据到子进程中。

所以fork在复制内存页的时候会大量的消耗CPU资源,如果复制的内存页越大,fork阻塞的时间就会越久。拷贝内存页完成,子进程与父进程指向相同的内存地址,这个时候就会放开主进程的阻塞,对外提供操作。每当有新的写命令,就会触发操作系统的COW写时复制机制,此时就会把这新的命令写到AOF日志缓冲区,等待数据重写完成后,重写的日志与缓冲区修改的数据进行合并,这样保证了父子进程之间的数据同步。

3.1. fork导致阻塞时长

正常情况 fork 耗时应该是每 GB 消耗 20ms 左右,当然也可以用 info stats 命令查看 latest_fork_usec 指标, 获取最近一次 fork 操作耗时, 单位微秒。

3.2. 如何避免
  • 调整 AOF 触发条件,比如从原来的 64 M,根据实际情况调大,降低 AOF 发生;
  • 减少单redis实例大小,尽可能降低到10G以内,越小相应fork速度越快;
  • 使用主从节点,AOF发生在从节点,从而对读写的主节点没有影响
  • linux内核优化,禁止使用:echo never > /sys/kernel/mm/transparent_hugepage/enable,如果父进程有大量的内存页写入,就证明你的子进程内存开销比较大,因为它会写内存副本,造成很大的内存开销;
  • 升级硬件,比如使用更好的CPU,从机械硬盘换成SSD;

总的来说,没有好不好,只有是否合适。软件系统的设计都是偏向于解决某个领域的问题,具体情况要看具体使用场景,比如可以考虑关闭AOF,当服务流量低峰时手动触发AOF。也可以从自身的业务出发尽可能减少写请求。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生技术爱好者社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 什么是AOF
  • 2. AOF重写又是怎么回事
    • 2.1. 写AOF文件
      • 2.2. AOF重写操作
        • 2.3. AOF重写发生条件。
        • 3. 如何避免AOF造成的影响
          • 3.1. 影响原因
            • 3.1. fork导致阻塞时长
              • 3.2. 如何避免
              相关产品与服务
              云数据库 Redis
              腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档