阻塞与故障排查
线上 Redis 变慢或异常,需要一套系统的方法快速定位根因。本章介绍排查工具与常见故障的定位思路,给出可复用的排查流程。
排查时先按延迟、内存、CPU、连接和集群状态分流,再收集 INFO、SLOWLOG、系统指标和客户端错误形成证据链。确认根因后再修改配置;如果指标恢复但原因未验证,应继续记录假设和反证,避免把偶然恢复当成修复完成。
1. 排查工具箱
| 工具 | 用途 | 开销 |
|---|---|---|
INFO | 服务器状态全貌 | 低 |
SLOWLOG | 慢查询日志 | 低 |
MONITOR | 实时命令流 | 高(生产慎用) |
CLIENT LIST | 客户端连接详情 | 中 |
redis-cli --latency | 持续 PING 的往返延迟 | 低 |
redis-cli --bigkeys | 大 Key 扫描 | 中(SCAN 遍历) |
DEBUG OBJECT key | 单 Key 的编码与引用信息 | 生产环境慎用;受版本、安全策略和命令禁用影响 |
MEMORY USAGE key | 单 key 内存占用 | 低 |
bash
# 快速全貌
redis-cli INFO all > /tmp/redis-info.txt
# 命令统计(找出耗时最高的命令)
INFO commandstats
# cmdstat_set:calls=1000000,usec=50000,usec_per_call=0.05
# cmdstat_keys:calls=10,usec=500000,usec_per_call=50000.00 ← 这个有问题2. 排查方法论
txt
观察现象 → 收集指标 → 提出假设 → 验证假设 → 修复 → 监控| 步骤 | 说明 |
|---|---|
| 观察现象 | 明确是延迟、内存还是 CPU 问题 |
| 收集指标 | 用 INFO、SLOWLOG 收集客观数据 |
| 提出假设 | 基于指标缩小范围(慢命令?fork?swap?) |
| 验证假设 | 用数据证实或推翻,不凭直觉 |
| 修复 | 替换慢命令、调配置、扩内存 |
| 监控 | 修复后持续观察,确认问题消除 |
3. 延迟突增排查
延迟突增是最常见的故障,按顺序排查:
3.1 慢命令
bash
SLOWLOG GET 10
# 如果看到 KEYS *、HGETALL 大 Hash → 用 SCAN 替代
# 如果看到 DEL 大 Key → 用 UNLINK 替代3.2 fork 停顿
bash
INFO stats | grep latest_fork_usec
# latest_fork_usec:150000 → fork 耗时 150ms,结合业务延迟基线判断
# 解决方案:
# 1. 根据页表规模、COW 和延迟预算评估实例拆分
# 2. 调整持久化触发条件并避开写入高峰
# 3. 评估副本分担持久化任务的可行性和数据恢复影响3.3 AOF fsync 阻塞
bash
# 检查 fsync 延迟
redis-cli INFO persistence | grep aof_delayed_fsync
# aof_delayed_fsync:5 → 5 次 fsync 延迟
# 解决方案:
# 1. appendfsync 改为 everysec(不要 always)
# 2. 使用 SSD 替代 HDD
# 3. 评估 no-appendfsync-on-rewrite;它会扩大重写期间的数据丢失窗口3.4 swap 导致的延迟
bash
# RSS 高于 used_memory 也可能来自分配器碎片,不能据此判定 swap
INFO memory | grep -E "used_memory|mem_fragmentation_ratio"
# 检查目标 Redis 进程实际换出的页(将 12345 替换为目标 PID)
awk '/^Swap:/ {sum += $2} END {print sum " kB"}' /proc/12345/smaps
# 检查系统 swap 使用量
grep -E "SwapTotal|SwapFree" /proc/meminfoswap 的解决:增加物理内存,或减小 maxmemory。
4. 内存异常排查
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 内存持续增长 | key 无 TTL 堆积 | INFO keyspace 看 key 数量趋势 |
| 碎片率高(>1.5) | 频繁增删 key | INFO memory 的 mem_fragmentation_ratio |
| 使用了 swap | 容器或主机可用内存不足 | 检查进程 smaps 的 Swap: 与系统 SwapTotal/SwapFree |
| 内存突增 | 大 Key 写入 | redis-cli --bigkeys 扫描 |
bash
# 查看各 DB 的 key 数量
INFO keyspace
# db0:keys=1000000,expires=800000,avg_ttl=300000
# db1:keys=50,expires=0,avg_ttl=0
# 查看内存分布
INFO memory
# used_memory:1073741824
# used_memory_rss:1610612736
# used_memory_peak:2147483648
# mem_fragmentation_ratio:1.505. CPU 飙升排查
| 排查点 | 命令 | 说明 |
|---|---|---|
| 高频命令 | INFO commandstats | 找出调用频繁、耗时高的命令 |
| Lua 脚本 | SLOWLOG | 脚本执行期间独占 CPU |
| 频繁 BGSAVE | INFO stats | fork 与 COW 消耗 CPU |
| 过期键风暴 | INFO stats | expired_keys 突增 |
bash
# 实时观察目标 Redis 进程 CPU(将 12345 替换为目标 PID)
top -p 12345
# Redis 内部 CPU 统计
INFO cpu
# used_cpu_sys:1234.56
# used_cpu_user:5678.906. 连接数异常
| 现象 | 可能原因 | 排查 |
|---|---|---|
| 连接数过高 | 连接池泄漏、短连接 | CLIENT LIST 统计 |
| 连接被拒 | 达到 maxclients | CONFIG GET maxclients |
| TIME_WAIT 堆积 | 频繁短连接 | ss -s 系统层面 |
bash
# 统计连接来源
CLIENT LIST | awk '{print $2}' | sort | uniq -c | sort -rn
# 查看最大连接数
CONFIG GET maxclients7. 集群故障排查
| 现象 | 可能原因 | 排查 |
|---|---|---|
| MOVED 重定向频繁 | 槽分配不均 | CLUSTER SLOTS |
| ASK 重定向 | 槽迁移中 | CLUSTER STATE |
| 节点下线 | 网络或内存问题 | CLUSTER NODES |
| 数据不一致 | 复制延迟 | INFO replication |