Redis

Redis 线上高频问题

·23 分钟阅读·9132 字
📋 目录

Redis 线上高频问题

核心概念 Redis 线上高频问题涵盖缓存穿透、击穿、雪崩、大 Key、热 Key、内存暴涨、慢查询、主从延迟等排查与解决方案。

覆盖:CPU高、内存溢出、主从同步故障、慢查询、连接打满、持久化阻塞、集群槽位异常、缓存雪崩/穿透/击穿、OOM、超时卡顿。

1. CPU 100% 高占用排查

1.1. 两大核心诱因

1.1.1. (1)主线程阻塞(单线程模型,最常见)

Redis 命令处理、RDB/AOF刷盘、主从全量同步、大key删除、大量keys/*scan阻塞主线程。
排查步骤:

  1. 查看慢查询 slowlog get 100,看是否存在 KEYS *HGETALL、超大集合遍历、大DEL;
  2. 观察持久化阻塞:
# 查看持久化耗时、fork阻塞
redis-cli info persistence
  • latest_fork_usec 数值几千上万:fork创建RDB子进程阻塞主线程;
  1. 查看主从同步:info replication,全量RDB同步时主线程大量写缓冲区CPU飙升;
  2. 监控实时命令:redis-cli monitor(线上慎用,会加重CPU)。

1.1.2. (2)子进程CPU打满

  • bgsave RDB压缩大量数据;
  • aof rewrite 重写整理大量AOF日志;
  • 大量持久化IO消耗内核CPU。

1.2. 排查命令

# 1. 慢查询
slowlog len
slowlog get 20

# 2. 实时命令统计(redis 6+)
redis-cli info stats | grep cmd

# 3. 查看fork阻塞时间
redis-cli info persistence | grep latest_fork_usec

# 4. 看热点大key
redis-cli --bigkeys

1.3. 优化方案

  1. 禁用 KEYS *,改用分页 SCAN/HSCAN/ZSCAN
  2. 超大Hash/Set拆分,避免一次性全量读取;
  3. 大key异步删除:UNLINK 替代 DEL
  4. 错开RDB/AOF rewrite业务高峰;
  5. 机器调高内存overcommit,减少fork阻塞;
  6. 读写分离,查询分流从库。

2. 内存相关问题(OOM、内存持续上涨、内存溢出、swap飙升)

2.1. 内存持续只涨不释放

原因:

  1. 大量过期key未主动淘汰,惰性删除;
  2. 大key堆积,过期后内存不会立刻释放;
  3. 持久化缓冲区、repl_backlog复制缓冲区占用;
  4. 客户端输出缓冲区溢出(主从同步、大量查询打满缓冲区)。

排查:

# 内存整体状态
info memory
# 各db key数量
info keyspace
# 扫描大key
redis-cli --bigkeys
# 查看客户端缓冲区
client list | grep -o 'output-buf=[0-9]*'

2.2. OOM Killer 杀死 Redis

触发条件:maxmemory 未配置,占用整机内存,系统OOM优先杀掉redis。
解决方案:

# redis.conf 强制限制内存
maxmemory 60gb
# 缓存场景淘汰策略
maxmemory-policy volatile-lru

2.3. swap 大量使用(si 数值飙升,性能暴跌)

内核频繁把redis内存交换到磁盘,读写延迟几十ms~秒级。
根因:内存不足、maxmemory设置过大、多进程抢占内存。
优化:

# 内核调小swap使用倾向
echo vm.swappiness=0 >> /etc/sysctl.conf
sysctl -p
# redis合理设置maxmemory,预留系统内存

2.4. 淘汰策略踩坑

  • allkeys-lru:所有key不分过期时间淘汰;
  • volatile-lru(缓存推荐):只淘汰带过期的key;
  • noeviction:内存满直接拒绝写入,业务报错,线上严禁使用。

3. 主从同步故障(频繁全量同步、同步延迟、断开、数据不一致)

3.1. 频繁触发全量RDB同步

排查:

info replication
# 对比 master_repl_offset、slave_repl_offset

诱因:

  1. repl-backlog-size 缓冲区过小,断开后offset超出环形缓冲区;
  2. 网络抖动,从库频繁断线重连;
  3. 主重启生成新replid,从库无法增量同步;
  4. 从库client-output-buffer溢出,主主动断开连接。

优化:

# 调大复制缓冲区
repl-backlog-size 128mb
# 调大从库输出缓冲区
client-output-buffer-limit slave 256mb 64mb 60

3.2. 主从同步延迟高

  1. 主写入QPS极高,单从追赶不上;
  2. 从库磁盘性能差,回放AOF/RDB慢;
  3. 链式复制层级过多;
  4. 从库CPU弱,大量命令回放阻塞。

定位:对比主从 repl_offset 差值持续拉大。

3.3. 主从数据不一致

  1. 人为在从库执行写命令(关闭replica-read-only);
  2. 主AOF/RDB持久化失败,重启丢失数据;
  3. 网络丢包导致同步命令截断;
  4. 低版本Redis同步BUG。

3.4. 主从自动断开

防火墙6379拦截、输出缓冲区溢出、TCP超时、内存OOM杀进程。

4. 大量连接异常(连接数打满、大量TIME_WAIT、客户端超时)

4.1. 连接数超限报错 Too many connections

排查:

# 当前客户端连接
info clients
client list

原因:

  1. 客户端连接未复用,短连接频繁创建;
  2. 连接池配置过小,并发打满;
  3. 未设置超时,闲置连接永久占用。

优化:

# 闲置连接自动释放300s
timeout 300
# 调高最大连接
maxclients 100000

业务侧:使用连接池,避免每次新建连接。

4.2. 大量 TIME_WAIT 端口耗尽

短连接高并发,内核端口回收慢。
内核调优:

net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535

4.3. 客户端读取超时

现象:业务大量 read timeout。
诱因:

  1. 主线程阻塞(大key、持久化、全量同步);
  2. 主从同步占用大量带宽;
  3. 网络延迟高、丢包。

5. 持久化阻塞(业务写入卡顿、延迟飙升)

5.1. RDB bgsave fork 阻塞主线程

fork创建子进程时拷贝页表,内存越大阻塞越久,latest_fork_usec 上万微秒。
优化:

  1. 避开业务高峰执行bgsave;
  2. 机器开启内存大页关闭、调整overcommit_memory=1;
  3. 改用AOF为主,降低RDB频率。

5.2. AOF rewrite 重写阻塞

大量过期数据,AOF文件持续膨胀,rewrite大量IO、CPU消耗。
参数调优:

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 折中刷盘策略 everysec
appendfsync everysec
no-appendfsync-on-rewrite yes

5.3. AOF 刷盘阻塞主线程

  • appendfsync always 每条写强制刷盘,性能极差;
  • everysec 每秒后台刷盘,推荐生产;
  • no 交给系统刷盘,宕机丢失最多30秒数据。

6. Redis Cluster 分片集群专属故障

6.1. 集群状态 fail 不可用

排查:

redis-cli -c --cluster check ip:6379
cluster info
cluster nodes

诱因:

  1. 某分片主库宕机,无可用从库未完成切换;
  2. 槽位未全部分配(slot 0-16383缺失);
  3. 节点之间端口不通(集群总线16379)。

6.2. MOVED / ASK 重定向报错

  1. MOVED:key所属槽永久迁移到其他主节点,客户端未缓存路由;
  2. ASK:槽正在迁移中,临时跳转;
    业务解决:客户端开启集群模式 -c,自动跳转。

6.3. 槽迁移卡顿、业务超时

rebalance迁移slot期间,对应key读写阻塞,低峰期执行迁移。

6.4. 分片主从切换失败

从库复制偏移量落后太多、网络不通、从库优先级过低,集群不提升从库为主。

7. 三大缓存经典问题:雪崩、穿透、击穿

7.1. 缓存雪崩

大量key同时过期,大量请求打透到DB,数据库崩溃。
解决方案:

  1. 过期时间增加随机偏移量;
  2. 多级缓存、限流、熔断;
  3. 永不过期热点key。

7.2. 缓存穿透

查询不存在key,绕过缓存直达DB(如id=-1、非法参数)。
解决方案:

  1. 空值缓存短期过期;
  2. 布隆过滤器拦截不存在key;
  3. 接口参数校验。

7.3. 缓存击穿

热点单一key过期,瞬间海量请求打数据库。
解决方案:

  1. 热点key永不过期;
  2. 分布式互斥锁互斥更新;
  3. 逻辑过期,后台异步刷新。

8. 慢查询 & 业务超时通用排查流程

标准排查步骤(线上通用):

  1. 查看慢日志 slowlog get,定位慢命令;
  2. 查看CPU、内存、swap指标,判断主线程是否阻塞;
  3. 查看持久化info,确认fork/rewrite是否阻塞;
  4. 主从场景查看同步延迟、repl_backlog;
  5. 查看客户端连接数、输出缓冲区是否溢出;
  6. 集群环境检查slot分配、节点状态;
  7. 网络层查看丢包、延迟、端口占用。

9. 常用排查命令汇总

# 基础全局状态
info server
info clients
info memory
info persistence
info replication
info stats

# 慢查询
slowlog len
slowlog get 50

# 大key扫描
redis-cli --bigkeys -h x.x.x.x -p 6379

# 集群检查
redis-cli --cluster check ip:6379
cluster info
cluster nodes

# 实时客户端
client list
client kill ip:port

# 监控流量(慎用,高并发加重负载)
redis-cli monitor

10. 线上通用稳定优化总结

  1. 禁止KEYS、HGETALL,使用SCAN系列分页;大key用UNLINK;
  2. 合理maxmemory+淘汰策略,关闭swap,预留系统内存;
  3. AOF everysec,错开RDB/rewrite业务高峰;
  4. 调大repl-backlog与slave输出缓冲区,减少全量同步;
  5. 读写分离,查询压力下放从库;
  6. 集群业务使用哈希标签,避免跨槽批量操作报错;
  7. 客户端使用连接池,设置闲置连接超时;
  8. 热点key打散、过期时间随机偏移,防雪崩击穿穿透;
  9. 监控核心指标:CPU、内存、swap、复制偏移、慢查询数量、连接数、fork阻塞耗时。完整排查手册

覆盖:CPU高、内存溢出、主从同步故障、慢查询、连接打满、持久化阻塞、集群槽位异常、缓存雪崩/穿透/击穿、OOM、超时卡顿。

11. CPU 100% 高占用排查

11.1. 两大核心诱因

11.1.1. (1)主线程阻塞(单线程模型,最常见)

Redis 命令处理、RDB/AOF刷盘、主从全量同步、大key删除、大量keys/*scan阻塞主线程。
排查步骤:

  1. 查看慢查询 slowlog get 100,看是否存在 KEYS *HGETALL、超大集合遍历、大DEL;
  2. 观察持久化阻塞:
# 查看持久化耗时、fork阻塞
redis-cli info persistence
  • latest_fork_usec 数值几千上万:fork创建RDB子进程阻塞主线程;
  1. 查看主从同步:info replication,全量RDB同步时主线程大量写缓冲区CPU飙升;
  2. 监控实时命令:redis-cli monitor(线上慎用,会加重CPU)。

11.1.2. (2)子进程CPU打满

  • bgsave RDB压缩大量数据;
  • aof rewrite 重写整理大量AOF日志;
  • 大量持久化IO消耗内核CPU。

11.2. 排查命令

# 1. 慢查询
slowlog len
slowlog get 20

# 2. 实时命令统计(redis 6+)
redis-cli info stats | grep cmd

# 3. 查看fork阻塞时间
redis-cli info persistence | grep latest_fork_usec

# 4. 看热点大key
redis-cli --bigkeys

11.3. 优化方案

  1. 禁用 KEYS *,改用分页 SCAN/HSCAN/ZSCAN
  2. 超大Hash/Set拆分,避免一次性全量读取;
  3. 大key异步删除:UNLINK 替代 DEL
  4. 错开RDB/AOF rewrite业务高峰;
  5. 机器调高内存overcommit,减少fork阻塞;
  6. 读写分离,查询分流从库。

12. 内存相关问题(OOM、内存持续上涨、内存溢出、swap飙升)

12.1. 内存持续只涨不释放

原因:

  1. 大量过期key未主动淘汰,惰性删除;
  2. 大key堆积,过期后内存不会立刻释放;
  3. 持久化缓冲区、repl_backlog复制缓冲区占用;
  4. 客户端输出缓冲区溢出(主从同步、大量查询打满缓冲区)。

排查:

# 内存整体状态
info memory
# 各db key数量
info keyspace
# 扫描大key
redis-cli --bigkeys
# 查看客户端缓冲区
client list | grep -o 'output-buf=[0-9]*'

12.2. OOM Killer 杀死 Redis

触发条件:maxmemory 未配置,占用整机内存,系统OOM优先杀掉redis。
解决方案:

# redis.conf 强制限制内存
maxmemory 60gb
# 缓存场景淘汰策略
maxmemory-policy volatile-lru

12.3. swap 大量使用(si 数值飙升,性能暴跌)

内核频繁把redis内存交换到磁盘,读写延迟几十ms~秒级。
根因:内存不足、maxmemory设置过大、多进程抢占内存。
优化:

# 内核调小swap使用倾向
echo vm.swappiness=0 >> /etc/sysctl.conf
sysctl -p
# redis合理设置maxmemory,预留系统内存

12.4. 淘汰策略踩坑

  • allkeys-lru:所有key不分过期时间淘汰;
  • volatile-lru(缓存推荐):只淘汰带过期的key;
  • noeviction:内存满直接拒绝写入,业务报错,线上严禁使用。

13. 主从同步故障(频繁全量同步、同步延迟、断开、数据不一致)

13.1. 频繁触发全量RDB同步

排查:

info replication
# 对比 master_repl_offset、slave_repl_offset

诱因:

  1. repl-backlog-size 缓冲区过小,断开后offset超出环形缓冲区;
  2. 网络抖动,从库频繁断线重连;
  3. 主重启生成新replid,从库无法增量同步;
  4. 从库client-output-buffer溢出,主主动断开连接。

优化:

# 调大复制缓冲区
repl-backlog-size 128mb
# 调大从库输出缓冲区
client-output-buffer-limit slave 256mb 64mb 60

13.2. 主从同步延迟高

  1. 主写入QPS极高,单从追赶不上;
  2. 从库磁盘性能差,回放AOF/RDB慢;
  3. 链式复制层级过多;
  4. 从库CPU弱,大量命令回放阻塞。

定位:对比主从 repl_offset 差值持续拉大。

13.3. 主从数据不一致

  1. 人为在从库执行写命令(关闭replica-read-only);
  2. 主AOF/RDB持久化失败,重启丢失数据;
  3. 网络丢包导致同步命令截断;
  4. 低版本Redis同步BUG。

13.4. 主从自动断开

防火墙6379拦截、输出缓冲区溢出、TCP超时、内存OOM杀进程。

14. 大量连接异常(连接数打满、大量TIME_WAIT、客户端超时)

14.1. 连接数超限报错 Too many connections

排查:

# 当前客户端连接
info clients
client list

原因:

  1. 客户端连接未复用,短连接频繁创建;
  2. 连接池配置过小,并发打满;
  3. 未设置超时,闲置连接永久占用。

优化:

# 闲置连接自动释放300s
timeout 300
# 调高最大连接
maxclients 100000

业务侧:使用连接池,避免每次新建连接。

14.2. 大量 TIME_WAIT 端口耗尽

短连接高并发,内核端口回收慢。
内核调优:

net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535

14.3. 客户端读取超时

现象:业务大量 read timeout。
诱因:

  1. 主线程阻塞(大key、持久化、全量同步);
  2. 主从同步占用大量带宽;
  3. 网络延迟高、丢包。

15. 持久化阻塞(业务写入卡顿、延迟飙升)

15.1. RDB bgsave fork 阻塞主线程

fork创建子进程时拷贝页表,内存越大阻塞越久,latest_fork_usec 上万微秒。
优化:

  1. 避开业务高峰执行bgsave;
  2. 机器开启内存大页关闭、调整overcommit_memory=1;
  3. 改用AOF为主,降低RDB频率。

15.2. AOF rewrite 重写阻塞

大量过期数据,AOF文件持续膨胀,rewrite大量IO、CPU消耗。
参数调优:

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 折中刷盘策略 everysec
appendfsync everysec
no-appendfsync-on-rewrite yes

15.3. AOF 刷盘阻塞主线程

  • appendfsync always 每条写强制刷盘,性能极差;
  • everysec 每秒后台刷盘,推荐生产;
  • no 交给系统刷盘,宕机丢失最多30秒数据。

16. Redis Cluster 分片集群专属故障

16.1. 集群状态 fail 不可用

排查:

redis-cli -c --cluster check ip:6379
cluster info
cluster nodes

诱因:

  1. 某分片主库宕机,无可用从库未完成切换;
  2. 槽位未全部分配(slot 0-16383缺失);
  3. 节点之间端口不通(集群总线16379)。

16.2. MOVED / ASK 重定向报错

  1. MOVED:key所属槽永久迁移到其他主节点,客户端未缓存路由;
  2. ASK:槽正在迁移中,临时跳转;
    业务解决:客户端开启集群模式 -c,自动跳转。

16.3. 槽迁移卡顿、业务超时

rebalance迁移slot期间,对应key读写阻塞,低峰期执行迁移。

16.4. 分片主从切换失败

从库复制偏移量落后太多、网络不通、从库优先级过低,集群不提升从库为主。

17. 三大缓存经典问题:雪崩、穿透、击穿

17.1. 缓存雪崩

大量key同时过期,大量请求打透到DB,数据库崩溃。
解决方案:

  1. 过期时间增加随机偏移量;
  2. 多级缓存、限流、熔断;
  3. 永不过期热点key。

17.2. 缓存穿透

查询不存在key,绕过缓存直达DB(如id=-1、非法参数)。
解决方案:

  1. 空值缓存短期过期;
  2. 布隆过滤器拦截不存在key;
  3. 接口参数校验。

17.3. 缓存击穿

热点单一key过期,瞬间海量请求打数据库。
解决方案:

  1. 热点key永不过期;
  2. 分布式互斥锁互斥更新;
  3. 逻辑过期,后台异步刷新。

18. 慢查询 & 业务超时通用排查流程

标准排查步骤(线上通用):

  1. 查看慢日志 slowlog get,定位慢命令;
  2. 查看CPU、内存、swap指标,判断主线程是否阻塞;
  3. 查看持久化info,确认fork/rewrite是否阻塞;
  4. 主从场景查看同步延迟、repl_backlog;
  5. 查看客户端连接数、输出缓冲区是否溢出;
  6. 集群环境检查slot分配、节点状态;
  7. 网络层查看丢包、延迟、端口占用。

19. 常用排查命令汇总

# 基础全局状态
info server
info clients
info memory
info persistence
info replication
info stats

# 慢查询
slowlog len
slowlog get 50

# 大key扫描
redis-cli --bigkeys -h x.x.x.x -p 6379

# 集群检查
redis-cli --cluster check ip:6379
cluster info
cluster nodes

# 实时客户端
client list
client kill ip:port

# 监控流量(慎用,高并发加重负载)
redis-cli monitor

20. 线上通用稳定优化总结

  1. 禁止KEYS、HGETALL,使用SCAN系列分页;大key用UNLINK;
  2. 合理maxmemory+淘汰策略,关闭swap,预留系统内存;
  3. AOF everysec,错开RDB/rewrite业务高峰;
  4. 调大repl-backlog与slave输出缓冲区,减少全量同步;
  5. 读写分离,查询压力下放从库;
  6. 集群业务使用哈希标签,避免跨槽批量操作报错;
  7. 客户端使用连接池,设置闲置连接超时;
  8. 热点key打散、过期时间随机偏移,防雪崩击穿穿透;
  9. 监控核心指标:CPU、内存、swap、复制偏移、慢查询数量、连接数、fork阻塞耗时。

关联文档