LATENCY 监控:捕捉 Redis 卡顿的延迟事件

举报
yd_287908631 发表于 2026/11/14 08:11:01 2026/11/14
【摘要】 开启 latency monitor,用 DOCTOR 定位卡顿根因

SLOWLOG 只能抓"某条命令执行得慢",但生产上另一类更隐蔽的卡顿来自命令之外:fork、AOF 刷盘、淘汰循环、碎片整理,这些系统级动作不在任何一条命令里,slowlog 全然无感。LATENCY 监控以"延迟事件"为单位记录这类尖刺,并自带一份分析报告。本文以 Redis 7 为准,讲清事件模型、四个子命令的用法和 DOCTOR 报告的读法。

一、它与 SLOWLOG 的分工

两者是互补关系,不是替代关系:

| 维度 | SLOWLOG | LATENCY 监控 |

| --- | --- | --- |

| 记录对象 | 单条慢命令 | 系统级延迟事件 |

| 阈值单位 | 微秒 | 毫秒 |

| 是否记录命令参数 | 是 | 否 |

| 典型问题 | 谁在执行慢命令 | 为什么所有命令都变慢 |

一句经验法则:批量请求同时慢、P99 抖动,查 LATENCY。两者都干净,再往网络、客户端和操作系统层找。

监控记录的延迟是主线程视角的墙钟时间:不管是命令在执行、在等锁、还是在等磁盘刷盘,只要超过阈值就会被记为一笔。这个口径与客户端体感到的"命令变慢"高度一致,也是它比 SLOWLOG 更贴近业务感受的原因。

两者还有一个数量级上的差别容易被忽略。SLOWLOG 的阈值单位是微秒,10 毫秒已经算"慢";LATENCY 的阈值单位是毫秒,默认建议 100 毫秒起。这意味着两者关注的不是同一类问题:SLOWLOG 抓的是"某条命令本身要几十毫秒",量级在毫秒到秒之间;LATENCY 抓的是"整个实例卡了超过 100 毫秒",量级在百毫秒到秒之间。把 latency-monitor-threshold 设成 1 毫秒,等于让 LATENCY 退化成一个大号的 SLOWLOG,记录的绝大多数是正常波动,真正的问题反而被淹没。

二、开启与事件类型

LATENCY 监控默认关闭,latency-monitor-threshold 默认 0。设为非零毫秒数后,任何超过该阈值的"事件"都会被记录:

CONFIG SET latency-monitor-threshold 100   # 单位毫秒

Redis 7 记录的主要事件类型:

  • command / fast-command:普通命令与 O(1)/O(log N) 快速命令的执行耗时;
  • fork:BGSAVE、AOF 重写时的 fork 耗时,与实例内存大小正相关;
  • aof-fsync-always:appendfsync always 策略下每次写都刷盘的耗时;
  • aof-write、aof-write-pending-fsync、aof-write-active-child、aof-write-alone:AOF 写入被拖慢的几种成因,分别对应"有 fsync 待处理""写发生在子进程期间""写是独占的";
  • aof-rewrite-diff-write、aof-rename:重写期间写增量文件、以及重命名文件的耗时;
  • expire-cycle、eviction-cycle、eviction-del:过期扫描、淘汰循环、以及删除被淘汰 key 本身的耗时;
  • rdb-unlink-temp-file:删除 RDB 临时文件的耗时;
  • active-defrag-cycle:碎片整理周期占用超预期。

两点补充说明。expire-cycle 指主动过期扫描单次耗时过长:过期周期每轮只花固定时间抽查 key,过期 key 密集堆积时单轮会被拉满;eviction-cycle 与 eviction-del 则是内存触顶后淘汰逻辑的耗时——前者看"淘汰决策与循环",后者看"真正删除 key 的释放动作",频繁出现说明容量已经不足,属于要扩容的信号。

每个事件类型各自维护一条时序记录(默认最多保留 160 个采样点),记录"何时发生、持续多久"。

三、四个子命令

LATENCY LATEST            # 每类事件最近一次的延迟
LATENCY HISTORY fork      # 某类事件的历史时序
LATENCY GRAPH fork        # ASCII 时序图
LATENCY DOCTOR            # 人类可读的综合诊断报告
LATENCY RESET             # 清空历史

LATENCY LATEST 的输出每行四列:

127.0.0.1:6379> LATENCY LATEST
1) 1) "fork"
   2) (integer) 1769300000     # 事件发生的时间戳
   3) (integer) 352            # 最近一次延迟,毫秒
   4) (integer) 512            # 该事件的历史最大延迟,毫秒

LATENCY GRAPH 用字符画出时间轴,直观看到毛刺集中在什么时段;LATENCY HISTORY 输出原始采样点,适合接入脚本做告警。日常巡检看 LATEST,复盘看 HISTORY 与 GRAPH。LATENCY DOCTOR 的报告结构是总览结论在前、逐事件展开在中、修复建议在后,把整段文本贴进工单或告警通知,比截图监控图更能让值班同事快速理解。

LATENCY GRAPH 的输出值得熟悉一下,它的信息密度比想象中高。格式是首行给出本次峰值与历史峰值,随后每个刻度一行,右侧用字符画出该采样点的高度:

127.0.0.1:6379> LATENCY GRAPH fork
fork - high 352 ms, low 2 ms (all time high 352 ms)
--------------------------------------------------------------------------------
  352 ms |                #
  176 ms |****************#************************************************
          1  2  3  4  5  6  7  8  9 10 11 12 13 14 15

纵轴是延迟刻度,横轴是采样序号,* 是该刻度以下的部分,# 标记超出该刻度的采样点。上例只有一处 # 顶到 352 ms,其余采样都在 176 ms 线以下——这种"孤峰"形态通常是某一次 BGSAVE 的 fork,而如果形态是"持续的锯齿",说明每一轮 fork 都慢,问题在实例规模而不是偶发因素。形态比具体数字更能反映性质,这也是 GRAPH 在复盘时比 HISTORY 更好用的原因。

采集 LATENCY LATEST 时要注意一个陷阱:它只给出每类事件的"最近一次"与"历史最大",如果连续两次采集之间发生了多次同类事件,中间的过程会丢失。要完整记录必须自己按秒轮询 LATENCY HISTORY 并与上次采集的最后一个时间戳比对,取出新增部分。简单地把 LATEST 存下来做趋势图,得到的曲线会是"最近一次的值",而不是"该时间段内的最大值",容易产生误判。

四、DOCTOR 报告怎么读

LATENCY DOCTOR 把所有事件汇总成一段诊断文本,直接给出建议,例如:检测到 fork 延迟高,说明实例内存偏大或写时复制严重,建议降低实例内存或单独一个从库做持久化;检测到 aof-write-active-child,指向 AOF 写盘与子进程并存导致 IO 争抢,建议检查磁盘负载或错开重写时间。它的建议是通用启发式,方向准确,但具体归因要再结合两处证据:

  1. INFO memory 的 used_memory 与 mem_fragmentation_ratio,对应 fork 与淘汰类事件;
  2. INFO persistence 的 aof_delayed_fsync 计数、current_cow_size,以及操作系统侧的磁盘 util 与 swap 使用,对应 AOF 与系统层事件。

提示:把 LATENCY LATEST 接入定时采集,任何事件的最大延迟超过业务容忍值就告警,比事后翻日志高效得多。

五、一次完整排障路径

线上收到"P99 抖动"类告警时,按这个顺序走一遍:

  1. LATENCY LATEST 看最近哪类事件在冒头,锁定事件类型与发生时间点;
  2. LATENCY HISTORY 与 LATENCY GRAPH 拉长时间轴,确认毛刺是周期性(比如整点的 AOF 重写)还是随机分布;
  3. 按事件类型分支定位:fork 查实例内存与持久化计划,aof-* 查磁盘负载与刷盘配置,eviction-* 查内存水位,fast-command / command 转去 SLOWLOG 找具体命令;
  4. 排除环境噪声:用 redis-cli --intrinsic-latency 60 在服务器本地采样 60 秒,量出系统自身的调度延迟基线;基线本身就有几十毫秒毛刺时,问题在宿主机(超售、NUMA、透明大页),不在 Redis 命令路径;
  5. 治理后保留 LATENCY LATEST 的定时采集,验证毛刺确实消失再关告警。

这条路径的价值在于分支清晰:事件类型直接指向责任层——内核、磁盘、内存还是命令本身,避免一上来就盲目重启换节点。

常见坑 / 最佳实践

  1. 默认是关闭的,上线先打开。 CONFIG SET latency-monitor-threshold 100 并写入配置文件;阈值单位是毫秒,别按 SLOWLOG 的微秒习惯填 10000。
  2. 阈值过低会产生大量噪音。 100ms 左右起步,观察一周后再按需调整;设成 1ms 会记录到海量正常波动,反而淹没真正的毛刺。
  3. LATENCY RESET 会清空历史。 想保留现场就先 LATEST 和 HISTORY 导出,别在排障脚本里随手 RESET。
  4. fork 事件高频出现不是延迟 bug,是容量问题。 实例内存越大 fork 越慢,根治靠拆实例、控制单实例内存在 10GB 以内量级。
  5. eviction-cycle 事件频繁说明内存不够用了。 这时优先扩容或调淘汰策略,而不是纠结毫秒数。

小结

  • LATENCY 监控补齐 SLOWLOG 的盲区,记录 fork、AOF 刷盘、淘汰循环等系统级延迟事件。
  • 默认关闭,latency-monitor-threshold 单位毫秒,生产建议 100ms 起步。
  • LATEST 看现状、HISTORY/GRAPH 看时序、DOCTOR 给诊断,巡检告警挂 LATEST。
  • DOCTOR 的建议指方向,最终归因要结合 INFO memory、INFO persistence 与操作系统指标。
  • 与 SLOWLOG 的分工:单条慢查命令,批量抖动查事件。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。