判断 Redis 性能瓶颈:CPU、内存还是网络?

判断 Redis 性能瓶颈:CPU、内存还是网络?

三种常见瓶颈

Redis 的性能瓶颈通常来自三个方面:CPU内存网络。不同瓶颈有不同的症状和解决方案。准确地判断瓶颈类型是优化的第一步。

瓶颈判断流程图

Redis 响应变慢?
│
├─ CPU 使用率 > 80%?─── 是 ───→ CPU 瓶颈
│                                ├─ 单线程 CPU 跑满
│                                └─ Fork 进程占 CPU
│
├─ 内存使用率 > 80% 且 碎片率高?─── 是 → 内存瓶颈
│                                       ├─ 内存不足 → 淘汰/swap
│                                       └─ 碎片严重 → 内存浪费
│
├─ 带宽使用率接近上限?─── 是 → 网络瓶颈 → 提升带宽或限流
│
└─ 无明显资源瓶颈? → 其他原因
   ├─ 慢命令(BigKey)
   ├─ 过期 key 清理
   └─ 主从同步延迟

详细判断方法

1. CPU 瓶颈判断

使用 top 命令观察

# 查看 Redis 进程 CPU 使用
top -p $(pgrep -x redis-server)

# Redis 单线程,CPU 使用率 = 100% × CPU 核心数
# 如 4 核服务器,Redis 最多用 100% 算满

使用 INFO CPU

redis-cli INFO CPU | grep used_cpu_sys
redis-cli INFO CPU | grep used_cpu_user
# 计算前后差值(采样间隔),如果 user+sys 时间/真实时间接近 1
# 说明 CPU 是瓶颈

CPU 瓶颈判断指标

import time

def is_cpu_bottleneck(r):
    """判断是否 CPU 瓶颈"""
    info1 = r.info('cpu')
    time.sleep(5)
    info2 = r.info('cpu')

    cpu_sec = (info2['used_cpu_sys'] - info1['used_cpu_sys']) + \
              (info2['used_cpu_user'] - info1['used_cpu_user'])

    # CPU 利用率 = cpu_sec / 5 (采样间隔)
    cpu_usage = cpu_sec / 5
    return cpu_usage > 0.8  # 大于 80% 视为 CPU 瓶颈

CPU 瓶颈的症状
– QPS 无法提升,达到上限(与服务器性能相关)
– top 显示 Redis 进程 CPU 占用接近 100%
– 延迟抖动但无明显慢查询
– 增加并发数不能提升吞吐量

2. 内存瓶颈判断

关键指标

redis-cli INFO MEMORY
# 1. used_memory → 接近 maxmemory?
# 2. mem_fragmentation_ratio → 过高?
# 3. evicted_keys → > 0 表示正在淘汰

memory 瓶颈判断

def is_memory_bottleneck(r):
    info = r.info('memory')
    used = info['used_memory']
    maxmem = info['maxmemory']
    evicted = info['evicted_keys']
    frag = info['mem_fragmentation_ratio']

    # 内存使用率 > 80%
    memory_high = (used / maxmem) > 0.8 if maxmem > 0 else False

    # 有淘汰发生
    has_eviction = evicted > 0

    # 碎片率过高
    high_frag = frag > 2.0

    return memory_high or has_eviction or high_frag

内存瓶颈的症状
– 日志中出现 Can't save in background: fork: Cannot allocate memory
– QPS 下降伴随大量过期 key 淘汰
– 磁盘 IO 高(正在 swap)
– 内存碎片率 > 1.5 或 < 1.0

3. 网络瓶颈判断

使用网络工具

# 查看网络带宽
sar -n DEV 2 5
# IFACE   rxpck/s   txpck/s   rxkB/s   txkB/s
# eth0    50000.00  50000.00  6250.00  6250.00
# 千兆网卡上限约 125MB/s

# 查看是否有丢包
netstat -s | grep -i "drop\|overflow\|retransmit"

网络瓶颈判断

def is_network_bottleneck(r, bandwidth_mbps=1000):
    """判断是否网络瓶颈"""
    info = r.info('stats')
    input_kbps = info['instantaneous_input_kbps']
    output_kbps = info['instantaneous_output_kbps']

    total_kbps = input_kbps + output_kbps
    total_mbps = total_kbps / 1000

    return total_mbps > bandwidth_mbps * 0.8  # 超过 80% 带宽

网络瓶颈的症状
– QPS 不高但响应慢
– 单次 bigkey 操作后延迟飙高
– 客户端报 connection timeout
– 带宽监控显示接近上限

4. 其他瓶颈信号

磁盘 I/O 瓶颈(持久化时):

# 查看磁盘 IO 情况
iostat -x 2 5 | grep -E "sd|nvme"
# %util 接近 100% 说明磁盘是瓶颈

命令延迟瓶颈

# 查看命令耗时分布
redis-cli INFO COMMANDSTATS

# 输出示例
cmdstat_set:calls=100000,usec=500000,usec_per_call=5.00
cmdstat_get:calls=200000,usec=800000,usec_per_call=4.00
cmdstat_keys:calls=10,usec=5000000,usec_per_call=500000.00
# ↑ KEYS 命令平均 500ms!严重问题

实战判断流程

def diagnose_redis(r):
    """Redis 瓶颈诊断"""
    print("=" * 50)
    print("Redis 瓶颈诊断报告")
    print("=" * 50)

    info = r.info('server')
    print(f"版本: {info['redis_version']}")

    # 1. CPU 检查
    cpu_info = r.info('cpu')
    qps = r.info('stats')['instantaneous_ops_per_sec']
    print(f"\n1. CPU 状态:")
    print(f"   当前 QPS: {qps}")
    if qps > 50000:
        print(f"   高负载,注意 CPU 可能成为瓶颈")

    # 2. 内存检查
    mem = r.info('memory')
    max_mem = mem['maxmemory']
    used = mem['used_memory']
    pct = used / max_mem * 100 if max_mem else 0
    print(f"\n2. 内存状态:")
    print(f"   使用: {used/1024/1024:.0f}MB / {max_mem/1024/1024:.0f}MB ({pct:.0f}%)")
    print(f"   碎片率: {mem['mem_fragmentation_ratio']:.2f}")
    print(f"   淘汰数: {mem['evicted_keys']}")

    if pct > 80:
        print(f"   ⚠️ 内存使用率过高")

    # 3. 慢查询检查
    slow = r.slowlog_get(5)
    if slow:
        print(f"\n3. 最近慢查询:")
        for s in slow:
            cmd = ' '.join(s['command'].decode().split()[:3])
            dur = s['duration'] / 1000
            print(f"   {dur:.1f}ms - {cmd}")
    else:
        print(f"\n3. 慢查询: 无")

    # 4. 连接检查
    clients = r.info('clients')
    print(f"\n4. 连接状态:")
    print(f"   当前连接: {clients['connected_clients']}")
    print(f"   拒绝连接: {clients['rejected_connections']}")

    return "诊断完成"

各瓶颈对应的解决方案

瓶颈类型 解决方案
CPU 瓶颈 升级 CPU/使用 Redis Cluster/读分离
内存瓶颈 扩容/优化数据结构/设置合理淘汰策略
网络瓶颈 升级带宽/压缩数据/就近部署
磁盘 I/O 使用 SSD/调整持久化策略
命令瓶颈 优化慢查询/避免 BigKey

面试要点

  • CPU 瓶颈的信号:Redis 进程 CPU > 80%、QPS 无法继续提升
  • 内存瓶颈的信号:used_memory 接近 maxmemory、evicted_keys > 0、碎片率异常
  • 网络瓶颈的信号:带宽使用率 > 80%、单次大操作后延迟飙高
  • 使用 INFO 命令 加外部监控(top、iostat、sar)综合判断
  • 启动时确保关闭 THP、调整 overcommit 等内核参数
© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容