Redis 缓存命中率 99% 但偶发超时,你会排查哪些指标

解读

  1. 命中率 99% 只能说明“读请求里 1% 穿透到后端”,不代表 Redis 本身没有性能抖动。
  2. 偶发超时(>RT 阈值或连接超时)往往落在 P99.9 或 P100,压测报告里容易被平均响应时间掩盖。
  3. 国内面试常把“缓存命中率”当陷阱,考察候选人能否跳出“命中率=一切”的思维,从全链路、资源、调度、网络、Redis 内部事件、客户端行为六个维度定位“毛刺”。
  4. 回答要体现“可观测→定界→定量→验证”完整思路,并给出具体指标与命令,避免只背“slowlog”一词。

知识点

  • Redis 事件模型:单线程命令执行 + BIO/IO 线程异步刷盘、lazy-free、AOF fsync。
  • 慢查询与延迟监控:slowlog、latency-monitor、latency doctor、–intrinsic-latency。
  • 系统资源:CPU 抢占、NUMA、swap、透明大页、网络软中断、带宽打满、TCP 重传。
  • 内存子系统:used_memory/rss/peak、碎片率、eviction、fork 时 copy-on-write 峰值延迟。
  • 持久化策略:AOF everysec 的 fsync 阻塞、rewrite 期间 fork 延迟、RDB 快照落盘。
  • 连接层:maxclients、TCP backlog 溢出、连接数突增、连接池参数(timeout、maxIdle、maxTotal)。
  • 热 key & 大 key:单个 key QPS > 10k 或 value > 10 MB 时,容易在单线程模型里造成“长尾”。
  • 客户端行为:pipeline 长度、一次 mget 过大、本地 GC、DNS 解析、Failover 重试窗口。
  • 公有云特性:弹性缓存实例的“CPU 信用”耗尽、跨可用区访问、SLB 限流。
  • 可观测体系:Prometheus + Grafana 看 P99 latency、node_exporter、redis_exporter、skywalking/jaeger 链路追踪。

答案

我会按“先外围后内部、先指标后根因”的顺序,在 5 分钟内给出可落地的排查清单:

  1. 确认超时定义

    • 业务日志里超时是“连接超时”还是“读超时”?阈值多少?对应接口的 TP99 基线是多少?
    • 用 redis-cli –latency-history 或 redis-cli –latency-dist 实时看 Redis 侧延迟分布,确认毛刺是否与业务超时对齐。
  2. 客户端指标

    • 连接池利用率:Jedis 看 JMX 属性 numActive/numWaiters;Lettuce 看 metrics 的 pending 队列。
    • 命令 RT 分位:用 Micrometer 输出 redis_command_duration_seconds{quantile=“0.999”},看是否出现阶梯状跳点。
    • 重试次数:Lettuce/Jedis 集群版在 MOVED/ASK 或断线时的重试次数,重试放大毛刺。
    • 本地 GC:如果客户端与 Redis 同机房但仍有 20 ms 级停顿,优先看 Young GC/Full GC 日志。
  3. 网络层指标

    • sar -n TCP,ETCP 1 看 tcpRetransSegs/tcpInSegs,重传率 >0.1% 即可导致随机超时。
    • iftop/iptraf 确认是否带宽跑满,云主机内网峰值 1.5 Gbps 被打满时 RT 可抖动到百毫秒。
    • 查看云监控“连接数”和“ENI 小包量”,部分云厂商对每秒小包数有限流,触发丢包。
  4. Redis 实例层指标(redis_exporter 核心)

    • instantaneous_ops/sec 与 cpu_used_percent:单线程吃满 100% 时,P99 会陡增。
    • used_memory_rss / used_memory 比值 >1.5 代表碎片高,触发频繁 realloc。
    • evicted_keys 与 expired_keys:即使命中率 99%,若出现突发 eviction,会阻塞事件循环。
    • latest_fork_usec:RDB/AOF rewrite 时 fork 耗时,超过 10 ms 即可造成请求堆积。
    • aof_delayed_fsync 计数器持续增长,说明磁盘 IO 拖慢主线程。
    • slowlog 按“命令耗时*次数”加权排序,关注 mget、keys、eval、zrangebyscore 等大 O 操作。
    • latency-monitor 结果:eventName=”fork” 或 ”aof-fsync” 出现 50 ms+ 的样本,即可定界持久化问题。
  5. 热 key / 大 key

    • 用 redis-cli –hotkeys(4.0+)或自研 hotkey 探针,拿到 top10 热 key QPS。
    • 对 value 做 memory usage key,>1 MB 且 QPS>5000 即可判定为“大 key+热 key”组合,需拆 key 或本地缓存。
  6. 持久化与副本

    • 主库查看 config get appendfsync 是否为 everysec;从库查看 rdb_last_save_time 是否落在超时点附近。
    • 若采用“Redis + 哨兵”或“阿里云主从版”,在 master 宕机迁移瞬间,客户端需要重新握手,超时窗口≈failover-timeout+cluster-node-timeout,需核对 client-timeout 是否小于该值。
  7. 系统级

    • top -H 看 redis-server 线程,确认是否被其他进程抢占;taskset -c -p 检查是否绑核。
    • cat /proc/vmstat | grep pgsteal,观察是否因内存紧张触发 swap。
    • 关闭透明大页:echo never > /sys/kernel/mm/transparent_hugepage/enabled,避免 fork 时延迟膨胀。
  8. 复现与验证

    • 用 redis-benchmark -c 100 -n 1000000 –latency -P 5 持续压测,同时后台执行 BGSAVE,观察 P99 是否从 0.5 ms 跳到 30 ms+。
    • 若确定是 fork 导致,可调大 repl-backlog-size、改用无盘复制 diskless=yes,或低峰期做 RDB;
    • 若是热 key,用本地 caffeine 缓存 + 消息队列异步更新,压测验证热 key QPS 下降 90%,超时消失。

通过以上指标,可在 15 分钟内完成“是否网络→是否fork→是否热key”三级定界,给出量化证据并推动优化落地。

拓展思考

  1. 云原生场景:
    如果 Redis 以 sidecar 容器跑在 K8s 上,还需检查 cgroup cpu quota Burst 策略、throttle 次数,以及 CNI 插件的 veth 包复制延迟。
  2. 读写分离架构:
    在“一主多从”+“读写分离”模式下,偶发超时可能来自从库复制延迟导致脏读,需监控 master_link_down_since_seconds 与 slave0lag。
  3. 多级缓存一致性:
    本地缓存+Redis+DB 三层架构中,若采用 Cache-Aside 且更新失败重试次数设置不当,可能在热点变更瞬间引发“缓存踩踏”,此时需引入分布式锁或异步消息队列削峰。
  4. 压测模型修正:
    传统“恒定并发”模型容易掩盖“突发 QPS”带来的瞬时排队;建议使用“脉冲模型”或“阶梯模型”复现毛刺,并在脚本里打印 P99.9 而不是只看 TPS。
  5. 业务可接受性评估:
    金融支付场景下 P99 要求 <5 ms,而内容推荐可放宽到 P99 <50 ms;优化前必须和产品、运维一起确认 SLA,避免过度调优。