Redis常见阻塞原因总结
Redis 可能出现阻塞的情况主要包括以下几种原因,并针对不同的场景提供优化方案:
1. 慢查询阻塞
原因
- 执行耗时较长的命令,如
keys *
、hgetall
、smembers
、flushall
。 - 查询的数据量过大,导致单个命令执行时间过长。
- CPU 资源占用过高,影响 Redis 的响应速度。
优化方案
-
使用
SCAN
替代KEYS
,避免一次性扫描整个数据库。 -
使用
HSCAN
、SSCAN
、ZSCAN
代替HGETALL
、SMEMBERS
等大数据操作。 - 优化数据结构,减少大 Key 的使用,改用分片存储。
-
开启慢查询日志(
slowlog-log-slower-than
参数),排查耗时操作并优化。
2. 持久化(RDB/AOF)阻塞
原因
- RDB 触发
BGSAVE
进程时,fork 进程占用大量 CPU 和内存。 - AOF 追加模式下,AOF 文件过大,重写(
BGREWRITEAOF
)时影响性能。 - AOF 同步写入 (
appendfsync always
) 可能导致 I/O 阻塞。
优化方案
-
调整 RDB 触发策略
,避免频繁 fork 进程:
- 适当延长
save
配置中的触发时间间隔。 - 业务高峰期可临时关闭自动 RDB 触发,改为手动触发。
- 适当延长
-
AOF 配置优化:
- 使用
appendfsync everysec
代替always
,减少磁盘 I/O。 - 定期
BGREWRITEAOF
避免 AOF 过大。 - 业务高峰期避免 AOF 重写,改为低峰时段执行。
- 使用
3. 内存不足导致 OOM(Out of Memory)
原因
- 数据增长超出可用内存,Redis 进程可能被 OOM 终止。
- 内存淘汰策略未配置,导致无法存入新数据。
优化方案
-
设置
maxmemory
限制 Redis 的最大内存,避免超过物理机可用内存。 - 选择合适的淘汰策略:
-
volatile-lru
(淘汰最近最少使用的可过期 key)。 -
allkeys-lru
(淘汰所有 key 中最近最少使用的)。 -
volatile-ttl
(淘汰快过期的 key)。 -
noeviction
(禁止淘汰,超出内存后返回错误)。
-
-
使用数据压缩(如
zstd
、snappy
)减少大 key 占用的空间。 - 定期清理无用数据,减少 Redis 负担。
4. 过多客户端连接
原因
- 短连接频繁创建,导致 Redis 处理大量 TCP 连接,增加 CPU 开销。
-
maxclients
限制过低,导致新连接被拒绝。
优化方案
-
使用连接池,如
JedisPool
(Java)、hiredis
(C)。 -
提升
maxclients
配置,避免连接数过低导致客户端无法访问。 -
开启
timeout
设置,自动关闭长时间未活跃的连接,减少资源占用。
5. 事务(MULTI/EXEC)阻塞
原因
- 事务(
MULTI
+EXEC
)中的命令过多,导致单个事务执行时间过长。 - 在
WATCH
监视的大 key 变更时,可能导致大量请求重试。
优化方案
-
避免事务中包含 O(n) 复杂度的命令(如
LRANGE
、HGETALL
)。 - 拆分事务,减少每个事务的执行时间。
- 避免大 key 监视,改用更细粒度的数据结构。
6. Lua 脚本执行阻塞
原因
- Redis 单线程执行 Lua 脚本,长时间运行的脚本会阻塞其他请求。
-
EVAL
语句包含 O(n) 复杂度操作,影响整体性能。
优化方案
-
使用
EVALSHA
复用已加载的 Lua 脚本,避免重复编译。 -
限制 Lua 脚本的执行时间,可使用
redis-cli --intrinsic-latency
进行监测。 - 复杂计算逻辑迁移到应用层,减少 Redis 计算压力。
7. 网络带宽/流量过高
原因
-
MONITOR
命令开启时,Redis 会记录所有请求,影响性能。 - Redis 传输的数据量过大,可能导致带宽不足。
优化方案
-
关闭
MONITOR
,避免实时记录影响性能。 -
启用
TCP_NODELAY
,减少 TCP 延迟。 -
使用
pipeline
进行批量请求,减少网络往返次数。 -
优化数据结构
,减少大 key 的传输,例如:
- 使用
HyperLogLog
代替Set
进行基数统计。 - 用
Bitmaps
代替List
进行状态记录。
- 使用
总结
问题类型 | 优化方案 |
---|---|
慢查询 | 使用 SCAN 代替 KEYS ,优化数据结构 |
持久化 | 调整 RDB 触发策略,优化 AOF 配置 |
内存不足 | 配置 maxmemory ,使用合适的淘汰策略 |
连接过多 | 使用连接池,提高 maxclients
|
事务阻塞 | 拆分事务,避免大 key 监视 |
Lua 阻塞 | 限制脚本执行时间,优化计算逻辑 |
网络流量 | 关闭 MONITOR ,使用 pipeline
|
通过这些优化手段,可以有效减少 Redis 阻塞,提高系统性能和稳定性。