Redis 偶发尖刺,官方 latency 清单里哪几项最容易中招?

p99 忽然翘一截,业务偶发超时,Redis 进程 CPU 却未必打满。这种尖刺比「一直慢」难抓。Redis 文档《Diagnosing latency issues》开头就给了一份短清单,后面再展开慢命令、透明大页、fork、AOF 等。下面按清单把常见中招点摊开,不写某家云厂商的未核数字。

清单五条在说什么

文档「I’ve little time, give me the checklist」大致是这几步:

  • 用 Slow Log 查有没有拖住服务器的慢命令。
  • 若在旧式 EC2 一类环境,注意 fork 过慢的问题。文中建议较新的 HVM 实例。
  • 关掉透明大页(Transparent Huge Pages):echo never > /sys/kernel/mm/transparent_hugepage/enabled,并重启 Redis 进程。
  • 用 redis-cli --intrinsic-latency 量运行环境的固有延迟——必须在跑 Redis 的那台服务器本机执行,不是在你的笔记本上对着远程实例敲。这个模式下 cli 甚至不连服务器,只测内核/虚拟化给进程调度留下的空洞。参数是测试秒数,文档示例用 100,跑得越久越容易撞到尖刺,也会吃满一个核。
  • 打开 Latency monitor,让实例自己采样阻塞路径,输出可读的延迟事件说明。

redis-cli --latency 则是连上实例测往返,和 intrinsic-latency 不是同一件事。固有延迟是下限:虚拟机、吵闹邻居负载高时,文档里举例能到数毫秒甚至更高量级,再怎么调 Redis 也破不了这个地板。

慢命令:KEYS 仍然是重灾区

Redis 大体是单线程处理请求,一条命令卡住,别的客户端都在等。文档点名:生产环境用 KEYS 是非常常见的延迟来源,文档写明它只适合调试。从 2.8 起应改用 SCAN / SSCAN / HSCAN / ZSCAN 做增量遍历。SORT、LREM、大集合上的 SUNION 一类复杂度高的命令,也要对照命令复杂度说明再决定打不打到大 key 上。

排查时先看 Slow Log。进程 CPU 偏高、流量却一般,文档也把它当成慢命令的常见信号。真有必须扫全库的维护活,考虑在副本上跑,别堵主线程。

透明大页、fork、落盘

fork 用于 BGSAVE 或 AOF 重写。主线程里的 fork 本身就可能引入延迟。页表拷贝成本跟实例内存有关。开启透明大页后,fork 之后少量写入就可能触发大页的写时复制,延迟和内存占用都会难看。文档给出的处理就是关掉 THP 再重启进程。

持久化档位也会换延迟形态。同一页用表概括了从「更安全」到「更偏延迟」的常见组合,例如:

  • AOF + 每次 fsync:很慢,只适合清楚代价的人。
  • AOF + 每秒 fsync:常见折中。还可配合 no-appendfsync-on-rewrite,重写时少打盘。
  • AOF + 从不主动 fsync:内核决定何时刷,盘压更小,尖刺风险另算。
  • 只靠 RDB:看你怎么配 save 触发。

everysec 时 fsync 在另一线程。若 fsync 拖太久,主线程最终仍可能被迫 write,文档把这点写成延迟来源之一。同机还有别的重 IO 进程时,更容易叠在一起。

别漏的环境因素

文档后半还写了 swap:Redis 页被换出后,碰 key 会卡在把页读回内存。可在 /proc/<pid>/smaps 里搜 Swap:,再用 vmstat 看 si/so 有没有在动。内存压力、别的进程抢页缓存,都可能把实例拖进这条路径。

大量 key 在同一秒过期,主动过期循环也可能短暂打满。文档对自适应过期有说明,用 EXPIREAT 扎堆同一时间戳时要留神。这些不一定每次尖刺都中,但清单走完仍无结果时,可以再往下翻。

网络往返和短连接也会把体感延迟抬高,但那和「服务器卡住几十毫秒」不是一类问题。文档建议能用管道、批量命令就少打来回,同机优先 Unix socket。这些优化在尖刺排查里排在 Slow Log / THP / fork 之后更合适。

你们线上尖刺最后多半落在慢命令、THP,还是 fork / AOF?本机跑 intrinsic-latency 时数字大概落在什么量级?