Redis 延迟定位:像侦探一样找出慢速根源

Redis 延迟定位:像侦探一样找出慢速根源

Redis 延迟来源谱系

当 Redis 响应变慢时,不能简单地归因于”Redis 变慢了”。以下是所有可能的延迟来源:

客户端
├── 网络延迟
├── 连接池耗尽
├── 序列化/反序列化
↓
网络传输
├── 带宽限制
├── 跨区域延迟
├── 丢包重传
↓
Redis 服务端
├── CPU 耗尽
├── 内存不足/swap
├── 慢命令
├── BigKey 操作
├── Fork(BGSAVE/BGREWRITEAOF)
├── 过期 key 清理
├── Rehash
├── 主从同步

定位工具包

1. Redis 内置延迟测试

# 测试 Redis 服务器内部延迟(不经过网络)
redis-cli --intrinsic-latency 100

# 测试网络延迟
redis-cli --latency -h host -p port

# 持续测试
redis-cli --latency -h host -p port -i 1

输出解读

# --intrinsic-latency 结果
# 最低内核级延迟:约 0.002ms(2 微秒)

# --latency 结果
# min: 0, max: 3, avg: 0.19 (毫秒)
# 平均 0.19ms 很健康,3ms 峰值偶尔出现可接受

2. LATENCY 子命令(Redis 3.0+)

# 查看所有延迟事件
redis-cli LATENCY LATEST

# 输出示例
1) 1) "fork"           -- 事件类型
   2) (integer) 1700000000  -- 时间戳
   3) (integer) 15342      -- 延迟(微秒)
   4) (integer) 15342      -- 最大延迟

2) 1) "command"
   2) (integer) 1700000000
   3) (integer) 10234
   4) (integer) 10234

# 查看延迟事件历史
redis-cli LATENCY HISTORY command
# 输出:每次记录的时间和延迟值

3. SLOWLOG 慢查询

# 慢查询阈值调到 1ms(微秒级)
CONFIG SET slowlog-log-slower-than 1000
# 检查慢查询
SLOWLOG GET 20

4. 客户端延迟归零法

# 在同一台机器上测试,排除网络影响
redis-benchmark -h 127.0.0.1 -n 100000 -c 1 -q

# 对比远程访问
redis-benchmark -h remote-host -n 100000 -c 1 -q
# 差值就是网络延迟的影响

常见延迟场景及定位

场景一:周期性延迟尖峰

症状:延迟每隔一段时间突然升高,然后恢复正常。

可能原因

  1. BGSAVE fork 阻塞
# 检查 fork 延迟
redis-cli LATENCY LATEST
# 如果看到 fork 事件的延迟达到数十毫秒,就是 BGSAVE 在作祟

# 查看最近 fork 耗时
redis-cli INFO STATS | grep latest_fork_usec

解决方案

# Redis 配置
repl-diskless-sync yes        # 无盘同步
rdbcompression yes            # 开启压缩减少 RDB 大小
# 调整 BGSAVE 频率
save 900 1
save 300 10
save 60 10000
  1. 过期 key 清理
# 查看过期 key 清理
redis-cli INFO STATS | grep expire

解决方案

# 避免大量 key 同时过期
# ❌ 同时设置过期
for key in keys:
    r.setex(key, 3600, value)  # 1 小时内全部过期

# ✅ 加随机偏移
for key in keys:
    ttl = 3600 + random.randint(0, 600)  # 1小时 ± 10分钟
    r.setex(key, ttl, value)

场景二:持续高延迟

症状:延迟持续偏高,找不到明显高峰。

  1. 内存 swap
# 检查是否发生了 swap
redis-cli INFO MEMORY | grep used_memory_rss
used_memory_rss:10737418240  # 10GB

# 对比 used_memory
# 如果 used_memory < used_memory_rss,说明正在使用 swap
# mem_fragmentation_ratio < 1 也提示可能 swap
  1. CPU 耗尽
# 查看 Redis 进程 CPU
top -p $(pgrep -x redis-server)
# %CPU 是否接近 100%

# 查看 QPS 是否异常高
redis-cli INFO STATS | grep instantaneous_ops_per_sec
  1. BigKey 操作
# 扫一下 bigkey
redis-cli --bigkeys
# 或者查看 slowlog
redis-cli SLOWLOG GET 10

场景三:偶尔的超时

  1. 连接池问题
# 检查连接池是否够用
pool_stats = {
    'active': len(pool._in_use_connections),
    'idle': len(pool._available_connections),
    'max': pool.max_connections
}
# 如果 active 接近 max,需要增大连接池
  1. 网络抖动
# 持续监控网络延迟
redis-cli --latency -h host -p port -i 5
# 观察 max/min 值,如果 max 远大于 avg,说明网络不稳定

延迟定位决策树

Redis 响应慢?
│
├─ 同一机器测试是否慢?─── 是 ───→ 检查 Redis 内部问题
│   │                              (slowlog, latency, bigkeys)
│   │
│   └─ 否 ───→ 网络问题
│               │
│               ├─ 内网延迟 > 1ms? 检查网卡/交换机
│               └─ 公网延迟高?检查跨区域部署
│
├─ 间歇性变慢?
│   │
│   ├─ 是否整点/每 10 分钟?──→ BGSAVE/AOF Rewrite
│   ├─ 是否有大批量过期?───→ 过期 key 清理
│   └─ 随机出现?───→ 网络抖动/其他进程干扰
│
└─ 持续变慢?
    │
    ├─ CPU 100%?───→ 检查 QPS 是否过高
    ├─ 内存不足?───→ 可能 swap,检查 mem_fragmentation
    └─ I/O 高?───→ 持久化写入瓶颈

延迟排查命令速查

# 一键排查脚本
echo "=== 网络延迟 ==="
redis-cli --latency -h localhost -p 6379 -i 3 | head -5

echo "=== 内部延迟 ==="
redis-cli --intrinsic-latency 100 | tail -1

echo "=== 慢查询 ==="
redis-cli SLOWLOG GET 5

echo "=== 命令统计 ==="
redis-cli INFO COMMANDSTATS

echo "=== Fork 耗时 ==="
redis-cli INFO STATS | grep latest_fork

echo "=== 内存 ==="
redis-cli INFO MEMORY | grep -E "used_memory|frag|maxmemory"

echo "=== QPS ==="
redis-cli INFO STATS | grep instantaneous_ops

面试要点

  • 延迟定位的核心思路:分层排查(客户端 → 网络 → 服务端)
  • redis-cli --intrinsic-latency 测试内核延迟
  • redis-cli --latency 测试网络 + Redis 延迟
  • Redis 内部延迟主要由 fork、slowlog、过期清理、rehash 导致
  • 周期性延迟通常是 fork 或 AOF rewrite 导致
  • 使用 LATENCY LATEST 查看 Redis 记录的延迟事件
© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容