Redis常见问题及对应解决方案(基础+性能+持久化+高可用全场景)
文章目录
- Redis常见问题及对应解决方案(基础+性能+持久化+高可用全场景)
-
- 一、基础使用类问题
-
-
- 键值过期策略理解错误,出现缓存脏数据 / 内存泄漏
-
- 大键 / 热键操作导致 Redis 单线程阻塞
-
- (1)大键问题解决
- (2)热键问题解决
-
- 缓存穿透:请求不存在的键,直接穿透到数据库
-
- 缓存击穿:热点键过期,大量请求同时穿透到数据库
-
- 缓存雪崩:大量缓存键同时过期,导致数据库被压垮
-
- 二、性能类问题
-
-
- Redis 响应延迟高(latency 高)
-
- Redis CPU 利用率过高 / 过低
-
- (1)CPU 利用率过高(接近 100%)
- (2)CPU 利用率过低,但 QPS 上不去
-
- 连接数耗尽:Redis 拒绝新连接
-
- 三、持久化类问题
-
-
- RDB 持久化导致 Redis 阻塞
-
- AOF 持久化导致性能下降,或 AOF 文件过大
-
- (1)AOF 写入导致 Redis 延迟高
- (2)AOF 文件过大,恢复时间长
-
- 持久化文件损坏,Redis 启动失败
-
- 持久化数据丢失,重启后数据不一致
-
- 四、高可用类问题(主从复制)
-
-
- 主从同步延迟,从节点数据落后主节点
-
- 主从全量同步频繁,占用大量资源
-
- 从节点只读配置失效,误写从节点
-
- 五、分布式类问题(Redis Cluster / 哨兵)
-
-
- 哨兵(Sentinel)故障切换失败
-
- Redis Cluster 脑裂问题
-
- Redis Cluster 跨槽操作报错(MOVED/ASK)
-
- Redis Cluster 分片不均,部分节点压力过大
-
- 六、运维监控类问题
-
-
- 缺乏监控,问题发生后无法快速定位
-
- 内存满了,Redis 出现数据淘汰 / 阻塞
-
- 生产环境直接执行危险命令,导致数据丢失 / 服务异常
-
- 七、Redis 常见问题排查思路总结
- 八、Redis 生产环境实践总结
Redis 作为高性能的内存键值数据库,在高并发、分布式场景下被广泛使用,但实际部署和使用中会因内存特性、单线程模型、网络 / 持久化机制、分布式架构等特点出现各类问题。
一、基础使用类问题
这类问题多出现于开发阶段,因对 Redis 数据结构、命令特性、使用规范理解不透彻导致,是最基础也最易规避的问题。
1. 键值过期策略理解错误,出现缓存脏数据 / 内存泄漏
问题表现 :设置了过期时间的键未被及时删除,要么读取到过期数据,要么过期键堆积导致内存占用过高;误以为DEL会主动清理过期键,或依赖被动过期导致热点键过期后阻塞。
核心原因 :Redis 过期键采用被动过期 + 主动定期删除结合的策略,并非过期立即删除:
被动过期:只有当访问该键时,才会检查是否过期,过期则删除;
主动删除:后台每隔 10ms 随机抽取部分过期键检查,删除已过期的,避免过期键堆积。
解决方案:
-
核心业务不依赖「过期键立即删除」,若需精准过期,可结合定时任务(如 Quartz) 主动调用
DEL/UNLINK删除; -
避免大量键在同一时间点过期 (如秒杀活动的缓存键),会导致主动删除阶段集中消耗 CPU,或访问时被动删除阻塞,可给过期时间加随机偏移量 (如
expire key 3600 + random(0,600)); -
Redis 4.0+ 推荐使用 UNLINK 替代 DEL,UNLINK 是异步删除,避免大键删除阻塞单线程。
最佳实践:过期时间根据业务特性合理设置,核心缓存设置双过期(Redis 过期 + 业务层兜底判断)。
2. 大键 / 热键操作导致 Redis 单线程阻塞
问题表现 :执行hgetall、lrange 0 -1、del bigkey等操作后,Redis 响应延迟飙升,其他命令被阻塞,甚至触发服务超时。
核心原因 :Redis 是单线程处理命令 ,对大键(如百万元素的 Hash/List/Set) 执行全量读取 / 删除 / 修改,会占用单线程大量 CPU 时间,导致其他命令排队;热键(单键 QPS 达万级以上)会让单线程一直处理该键的请求,其他请求被阻塞。
解决方案:
(1)大键问题解决
- 预防 :设计时避免单键存储大量数据,采用分桶策略 (如将一个百万元素的 Hash 拆分为 100 个小 Hash,key 为
user:info:1、user:info:2...); - 读取 :避免全量读取,使用分段命令(
hscan替代hgetall、lrange key 0 99替代lrange 0 -1、sscan替代smembers); - 删除 :4.0 + 用
UNLINK(异步),低版本手动分批次删除大键的元素后再删键; - 检测 :用
redis-cli --bigkeys定期检测大键,提前优化。
(2)热键问题解决
- 本地缓存兜底:将热键数据加载到应用本地内存(如 Caffeine),减少 Redis 请求;
- 热键分片 :将单热键拆分为多个子键(如
hot:key:1~hot:key:N),分散到不同 Redis 节点; - 使用代理层:如 Codis/Redis Cluster 的代理层,对热键请求做负载均衡;
- 限流降级:对热键的 QPS 做限流,避免超出 Redis 单线程处理能力。
3. 缓存穿透:请求不存在的键,直接穿透到数据库
问题表现 :大量请求查询 Redis 中不存在的键,Redis 直接返回空,请求全部穿透到后端数据库,导致数据库压力骤增甚至宕机(如恶意攻击、业务逻辑漏洞导致的无效查询)。
核心原因:缓存中无对应数据,且未做任何拦截,请求直达底层存储。
解决方案:
-
空值缓存 :对查询结果为 null 的键,在 Redis 中缓存空值 ,并设置短过期时间(如 5 分钟),避免缓存占用过多内存;
-
布隆过滤器:在应用层前置布隆过滤器,将所有可能存在的键提前加入过滤器,请求先经过过滤器,不存在则直接拦截,不访问 Redis 和数据库;
- 适用场景:数据量极大、查询频繁的场景(如电商商品 ID、用户 ID 查询);
- 注意:布隆过滤器存在误判率,需结合业务容忍度设置参数;
-
业务层校验:在请求到达缓存前,先做参数合法性校验,拦截明显的无效请求(如 ID 为 0、负数的查询)。
最佳实践:小流量场景用空值缓存,大流量高并发场景用布隆过滤器 + 空值缓存组合。
4. 缓存击穿:热点键过期,大量请求同时穿透到数据库
问题表现 :某个高热点键 在过期的瞬间,大量并发请求同时访问该键,Redis 中无数据,请求全部穿透到数据库,导致数据库瞬间压力飙升(区别于缓存穿透:击穿是单个热点键过期 ,穿透是大量无效键)。
核心原因:热点键过期,且无任何并发控制,导致请求同时直达数据库。
解决方案:
-
热点键永不过期 :对核心热键,不设置过期时间,由业务层主动更新 / 删除,避免过期导致的击穿;
-
互斥锁(分布式锁) :当应用查询到 Redis 中无数据时,先获取分布式锁 (如 Redis 的
SET NX EX),只有获取到锁的线程才去数据库查询并更新缓存,其他线程等待后重新查询缓存; -
缓存预热:在业务高峰前,主动将热点键加载到 Redis 中,并设置合理的过期时间,避免高峰期间过期。
最佳实践:核心热键采用永不过期 + 主动更新,非核心热键采用分布式锁。
5. 缓存雪崩:大量缓存键同时过期,导致数据库被压垮
问题表现 :某一时间段内,Redis 中大量键同时过期 ,大量请求穿透到数据库,数据库因无法承受高并发而宕机,引发整个系统雪崩(区别于击穿:雪崩是大量键 ,击穿是单个键)。
核心原因:缓存键的过期时间设置过于集中(如秒杀活动结束后所有商品缓存同时过期、批量设置过期时间为固定值)。
解决方案:
-
过期时间随机化 :给所有键的过期时间添加随机偏移量 ,避免集中过期(如原本过期时间 3600s,设置为
3600 + random(0, 600)s); -
缓存分级 :将缓存分为一级缓存(本地内存)+ 二级缓存(Redis),即使 Redis 缓存过期,一级缓存仍能兜底,减少数据库请求;
-
过期时间分层:将不同业务的缓存键设置不同的过期时间段,分散过期压力;
-
集群扩容 :提升 Redis 集群的处理能力,同时对数据库做读写分离、分库分表,提升数据库抗压能力;
-
限流降级:在缓存层和数据库层之间增加限流降级策略,当数据库压力超过阈值时,拒绝部分非核心请求,避免数据库宕机。
实践方案:过期时间随机化是基础方案,结合缓存分级 + 限流降级形成多层防护。
二、性能类问题
Redis 号称单线程十万 QPS,但实际使用中常出现 QPS 偏低、响应延迟高、CPU / 内存 / 网络利用率异常等性能问题,核心与单线程模型、配置优化、硬件资源相关。
1. Redis 响应延迟高(latency 高)
问题表现:Redis 命令执行耗时超过 1ms(正常情况下 Redis 单命令执行耗时 < 0.1ms),应用侧调用 Redis 出现超时。
核心原因 :分为Redis 内部原因 和外部原因,内部为主因:
内部:单线程被阻塞(大键操作、慢查询、持久化阻塞)、配置不合理(如内存分配策略、网络配置)、数据结构选择不当;
外部:服务器硬件资源不足(CPU / 内存 / 网络瓶颈)、Redis 部署在虚拟机 / 容器中导致的资源争用、网络延迟(跨机房 / 跨网段部署)。
解决方案:
- 排查慢查询:开启 Redis 慢查询日志,定位慢命令( slowlog get 10 ),优化 / 禁用慢查询(如替换全量读取为分段读取);
- 配置:
slowlog-log-slower-than 1000(记录耗时 > 1ms 的命令)、slowlog-max-len 1000(慢查询日志长度);
- 配置:
- 避免单线程阻塞 :禁用大键全量操作、用
UNLINK替代DEL、避免持久化(RDB/AOF)在高峰期间执行; - 优化 Redis 配置:
- 关闭透明大页(THP):
echo never > /sys/kernel/mm/transparent_hugepage/enabled(THP 会导致 Redis 内存分配耗时增加); - 优化网络配置:开启
tcp_tw_reuse(echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse)、增大somaxconn(echo 1024 > /proc/sys/net/core/somaxconn),避免 TCP 连接阻塞; - 调整内存分配器:使用
jemalloc(Redis 默认推荐),比malloc/tcmalloc更适合 Redis 的内存分配场景;
- 关闭透明大页(THP):
- 优化硬件和部署:
- Redis 部署在物理机上,避免虚拟机 / 容器的资源争用;
- 核心业务 Redis 与应用同机房同网段部署,避免跨机房网络延迟;
- 保证 Redis 服务器有足够的 CPU(单核即可满足单线程,多核可用于持久化 / 主从同步的后台线程)、内存(避免 swap);
- 排查 swap:Redis 内存使用超过物理内存,导致操作系统将 Redis 内存交换到磁盘(swap),swap 的 IO 速度远低于内存,会导致延迟飙升;
- 排查:
redis-cli info memory | grep swap,若used_memory_swap>0,说明触发了 swap; - 解决:增加物理内存、限制 Redis 最大内存(
maxmemory)、设置vm.swappiness=0(让操作系统尽量不使用 swap)。
- 排查:
2. Redis CPU 利用率过高 / 过低
(1)CPU 利用率过高(接近 100%)
核心原因 :单线程被密集的计算型命令占用(如SORT、ZINTERSTORE、大键的HSET/LPUSH)、慢查询、主动删除过期键过于频繁。
解决方案 :优化慢查询 / 计算型命令、拆分大键、调整过期键主动删除策略(hz 10调整为hz 20,避免过于频繁)。
(2)CPU 利用率过低,但 QPS 上不去
核心原因:网络瓶颈(如网卡带宽占满、TCP 连接数不足)、内存瓶颈(触发 swap)、应用侧请求方式不合理(如单连接串行请求,未使用连接池)。
解决方案:
- 应用侧使用Redis 连接池(如 Java 的 JedisPool/Lettuce),设置合理的连接数(根据 QPS 调整,一般为 20~50),避免频繁创建 / 销毁连接;
- 排查网络带宽:用
iftop查看网卡流量,若带宽占满,做 Redis 集群分片分散流量; - 解决 swap 问题,恢复内存性能。
3. 连接数耗尽:Redis 拒绝新连接
问题表现 :应用侧报错ERR max number of clients reached,无法新建 Redis 连接。
核心原因 :Redis 配置的最大连接数(maxclients)过小,或应用侧连接池配置不合理(如最小空闲连接数过大、连接未释放),导致已用连接数达到maxclients。
解决方案:
- 临时解决 :通过
redis-cli config set maxclients 10000增大最大连接数(需重启后持久化到redis.conf); - 应用侧优化 :检查连接池配置,确保连接复用 ,避免泄漏(如 Java 中关闭 Redis 连接时在
finally块中执行close()); - 排查无效连接 :用
redis-cli client list查看所有连接,过滤出空闲时间过长的连接(idle字段),通过client kill ip:port杀死无效连接; - 持久化配置 :在
redis.conf中设置maxclients 10000(根据服务器硬件调整,一般不超过 65535),同时设置timeout 300(自动关闭空闲 5 分钟的连接)。
三、持久化类问题
Redis 是内存数据库,默认数据仅存于内存,重启后会丢失,需通过 RDB(快照)和AOF(追加日志) 做持久化,但持久化过程中会出现性能损耗、数据丢失、文件损坏等问题。
1. RDB 持久化导致 Redis 阻塞
问题表现 :执行 RDB 快照(手动bgsave或自动触发)时,Redis 响应延迟飙升。
核心原因 :RDB 的bgsave 看似是后台执行,但创建子进程的fork 操作 是阻塞单线程 的,fork 的耗时与 Redis 的内存数据量正相关(内存越大,fork 越久);若服务器磁盘 IO 性能差,子进程写入 RDB 文件会占用 IO,导致 Redis 主进程的 IO 操作(如 AOF 写入)被阻塞。
解决方案:
- 优化 fork 操作:
- 减少 Redis 内存数据量(如设置
maxmemory、淘汰冷数据),降低 fork 耗时; - 开启
lazyfree-lazy-fork yes(Redis 6.0+),让 fork 更高效; - 避免在业务高峰期间触发 RDB,将自动 RDB 的触发时间设置在低峰期(如凌晨);
- 减少 Redis 内存数据量(如设置
- 优化磁盘 IO :将 RDB 文件存储在高速磁盘(如 SSD),提升写入速度;
- 集群分片:将大 Redis 实例拆分为多个小实例,每个实例的内存量减小,fork 耗时降低。
2. AOF 持久化导致性能下降,或 AOF 文件过大
(1)AOF 写入导致 Redis 延迟高
核心原因 :AOF 的写入策略配置过严(如appendfsync always),每次命令执行后都同步写入磁盘,磁盘 IO 成为瓶颈;AOF 重写时的 fork 操作和文件写入也会占用资源。
解决方案:
- 调整 AOF 同步策略:根据数据一致性要求选择合适的策略,兼顾性能和数据安全:
appendfsync no:由操作系统负责同步,性能最好,数据丢失风险最高;appendfsync everysec:每秒同步一次,默认配置,性能较好,最多丢失 1 秒数据;appendfsync always:每次命令都同步,数据零丢失,性能最差(仅适用于金融级强一致性场景);
- 优化 AOF 重写 :避免高峰期间重写,设置
auto-aof-rewrite-min-size 64mb(文件最小 64M 才重写)、auto-aof-rewrite-percentage 100(文件比上次重写增大 100% 时重写),并将 AOF 文件存储在 SSD。
(2)AOF 文件过大,恢复时间长
核心原因:AOF 记录所有写命令,长期运行后文件会持续增大,不仅占用磁盘空间,Redis 重启时加载 AOF 文件的时间也会极长。
解决方案:
- 开启 AOF 重写 :通过
bgrewriteaof手动重写,或开启自动重写,重写会生成一个精简的 AOF 文件(合并相同命令、删除无效命令); - RDB+AOF 混合持久化 (Redis 4.0+):开启
aof-use-rdb-preamble yes,AOF 文件的前半部分是 RDB 快照,后半部分是增量 AOF 日志,兼顾 RDB 的快速恢复和 AOF 的低数据丢失,重启时加载速度远快于纯 AOF。
3. 持久化文件损坏,Redis 启动失败
问题表现:Redis 重启时加载 RDB/AOF 文件报错,启动失败,提示文件损坏。
核心原因:持久化过程中 Redis 异常退出(如服务器宕机、kill -9 杀死 Redis 进程)、磁盘 IO 错误、文件系统损坏。
解决方案:
- 修复 RDB 文件 :Redis 官方未提供 RDB 修复工具,若 RDB 文件损坏,一般无法修复,只能恢复最近的完整备份;
- 修复 AOF 文件 :使用 Redis 自带的
redis-check-aof --fix [aof文件路径]工具修复,工具会删除损坏的命令行,修复后重启 Redis; - 预防措施:
- 避免强制杀死 Redis 进程,关闭时用
redis-cli shutdown(会先执行持久化,再退出); - 对持久化文件做定时备份(如每小时备份 RDB,每天备份 AOF),存储在独立的磁盘 / 服务器;
- 确保 Redis 服务器的磁盘健康,定期检查磁盘 IO 和文件系统。
- 避免强制杀死 Redis 进程,关闭时用
4. 持久化数据丢失,重启后数据不一致
问题表现:Redis 异常退出后,重启加载持久化文件,发现部分数据丢失,与业务侧数据不一致。
核心原因:
RDB:快照是定时生成的,两次快照之间的数会丢失;
AOF:同步策略为everysec/no时,操作系统未及时将日志写入磁盘,数据会丢失;
未开启持久化,或持久化配置错误(如 appendonly no )。
解决方案:
- 选择合适的持久化方案:
- 对数据一致性要求低(如缓存):仅开启 RDB,或不开启持久化;
- 对数据一致性要求高(如分布式锁、计数):开启RDB+AOF 混合持久化 ,AOF 同步策略设为
everysec;
- 结合主从复制:主节点开启持久化,从节点作为备份,即使主节点宕机,从节点可提升为主节点,避免数据丢失;
- 禁止关闭持久化:生产环境严禁为了性能关闭所有持久化,除非是纯缓存场景,且业务层有兜底恢复方案。
四、高可用类问题(主从复制)
主从复制是 Redis 实现高可用的基础,通过一主多从 实现读写分离、数据备份,但主从同步过程中会出现同步延迟、数据不一致、从节点宕机、主节点故障切换等问题。
1. 主从同步延迟,从节点数据落后主节点
问题表现 :从节点执行info replication查看master_repl_offset,与主节点的master_repl_offset差值过大,应用侧从从节点读取到旧数据。
核心原因:
网络延迟:主从节点跨机房 / 跨网段部署,网络带宽低、延迟高;
主节点写压力大:主节点 QPS 过高,写命令无法及时同步到从节点;
从节点性能差:从节点的 CPU / 内存 / 磁盘 IO 不足,无法及时处理主节点的同步数据;
主节点开启了repl-disable-tcp-nodelay yes,关闭了 TCP_NODELAY,导致 TCP 包延迟发送。
解决方案:
- 优化网络 :主从节点同机房同网段部署,保证网络带宽充足,避免跨机房同步;
- 读写分离优化 :将读请求分散到多个从节点,避免单个从节点压力过大;对强一致性读请求,直接路由到主节点,避免从节点数据落后;
- 提升从节点性能:从节点配置与主节点一致,使用 SSD 存储持久化文件,关闭从节点的持久化(若主节点已开启),减少从节点资源消耗;
- 开启 TCP_NODELAY :主节点配置
repl-disable-tcp-nodelay no(默认),让主节点立即将同步数据发送到从节点,降低延迟(会增加少量网络流量); - 限制主节点写压力:对主节点做分片,分散写请求,避免单主节点写 QPS 过高。
2. 主从全量同步频繁,占用大量资源
问题表现:主从节点频繁触发全量同步(而非增量同步),主节点频繁执行 bgsave 生成 RDB,从节点频繁加载 RDB,占用大量 CPU / 内存 / 网络资源。
核心原因:
主从节点的运行 ID(runid) 变化(如主节点重启、主从连接断开后重连,主节点 runid 改变);
主节点的复制积压缓冲区(repl_backlog_buffer) 过小,增量同步的 offset 超出缓冲区范围,只能触发全量同步;
主从连接频繁断开(如网络抖动、超时)。
解决方案:
- 增大复制积压缓冲区 :主节点配置
repl-backlog-size 1gb(根据主节点写流量调整,默认 1MB),让缓冲区能存储更多的增量同步数据; - 设置复制积压缓冲区过期时间 :
repl-backlog-ttl 86400(缓冲区无从节点连接时,保留 24 小时),避免缓冲区被快速释放; - 保证主从连接稳定 :优化网络,避免网络抖动,增大主从连接超时时间(
repl-timeout 60); - 主节点避免频繁重启:主节点重启会导致 runid 改变,触发全量同步,生产环境主节点尽量做优雅重启,或使用集群实现无感知故障切换。
3. 从节点只读配置失效,误写从节点
问题表现:从节点被配置为可写,应用侧误将写请求发送到从节点,导致主从数据不一致,且从节点重启后数据丢失。
核心原因 :从节点的slave-read-only(Redis 5.0-)/replica-read-only(Redis 5.0+)配置为no,未开启只读。
解决方案:
- 立即修复 :在从节点执行
config set replica-read-only yes,开启只读,持久化到redis.conf; - 应用侧优化:读写分离框架严格区分主从节点,写请求仅路由到主节点,读请求路由到从节点,避免误路由;
- 权限控制:为 Redis 设置密码,且主从节点使用不同的密码,从节点仅开放读权限。
五、分布式类问题(Redis Cluster / 哨兵)
当 Redis 需要支撑海量数据和超高并发时,需使用哨兵(Sentinel)**实现主从故障自动切换,或**Redis Cluster实现分布式分片,但分布式架构会引入新的问题,如故障切换失败、分片不均、脑裂、跨槽操作等。
1. 哨兵(Sentinel)故障切换失败
问题表现:主节点宕机后,哨兵集群未及时将从节点提升为主节点,导致服务不可用。
核心原因:
哨兵集群节点数不足(哨兵采用投票机制,至少需要 3 个哨兵节点才能保证投票有效性,避免脑裂);
哨兵与主节点的网络连接中断,但主节点实际未宕机(假宕机),哨兵误判;
从节点优先级过低 、slave-priority 0(无法被提升为主节点),或从节点同步延迟过大,不满足故障切换条件;
哨兵配置错误(如 down-after-milliseconds 过小,导致频繁误判;quorum 值设置过高,无法达成投票共识)。
解决方案:
- 哨兵集群部署规范 :至少部署3 个哨兵节点,分布在不同的服务器,避免单点故障;
- 优化哨兵配置:
down-after-milliseconds 30000(主节点失联 30 秒后才标记为宕机,避免网络抖动误判);quorum 2(3 个哨兵节点时,至少 2 个投票认为主节点宕机,才触发故障切换);- 给从节点设置合理的
slave-priority(数值越小优先级越高),避免设置为 0;
- 检查从节点状态 :确保从节点能正常同步主节点数据,同步延迟在合理范围内(
info replication查看lag字段,一般 < 1s); - 哨兵节点与主从节点同机房部署:减少网络延迟,避免假宕机。
2. Redis Cluster 脑裂问题
问题表现:Redis Cluster 的主节点因网络分区被分为两个部分,各部分都认为自己是合法的,导致数据写入到不同的主节点,出现数据不一致。
核心原因 :Redis Cluster 的节点投票机制 被触发,网络分区后,某一部分节点达到quorum(半数以上主节点),选举出新的主节点,而原主节点在另一分区仍接受写请求。
解决方案:
- 开启集群节点超时自动下线 :配置
cluster-node-timeout 30000(节点失联 30 秒后下线),cluster-require-full-coverage no(允许集群部分节点下线,仍提供服务); - 部署规范 :Cluster 的主节点数为奇数(如 3、5),保证投票时能快速达成共识,节点分布在不同的服务器 / 机架;
- 避免网络分区:优化网络架构,使用高可用的网络设备,减少跨网段部署。
3. Redis Cluster 跨槽操作报错(MOVED/ASK)
问题表现 :执行多键操作时(如mget key1 key2),报错MOVED xxx xxx.xxx.xxx.xxx:6379或ASK,操作失败。
核心原因 :Redis Cluster 采用哈希槽 分片,共 16384 个槽,每个键通过crc16(key) % 16384计算所属槽,多键操作的键必须在同一个槽中,否则会触发跨槽报错;单键操作若键的槽不在当前节点,会返回 MOVED/ASK,引导客户端到正确节点。
解决方案:
1.单键操作 :客户端使用集群感知的 Redis 客户端(如 Java 的 Lettuce、Jedis Cluster),客户端会自动处理 MOVED/ASK 重定向,无需业务层处理;
2.多键操作:
- 键哈希标签 :将多键操作的键设置为相同的哈希标签 ,如
key{user:100}、name{user:100},Redis 会根据{}内的内容计算槽,保证同槽; - 避免多键操作:将多键操作拆分为多个单键操作,由客户端分别执行;
3.批量操作 :使用pipeline(流水线)执行单键操作,提升批量处理效率,替代多键操作。
4. Redis Cluster 分片不均,部分节点压力过大
问题表现:Cluster 中部分节点的内存占用、QPS 远高于其他节点,出现负载不均。
核心原因:
键的哈希分布不均(如部分键的哈希槽集中在某几个节点);
热键集中在某一个节点的哈希槽中;
手动分配槽时,槽分配不均。
解决方案:
- 优化键设计:避免键的哈希值过于集中,使用随机化的键名,分散哈希槽;
- 热键分片:将热键拆分为多个子键,使用不同的哈希标签,分散到不同节点;
- 重新分配槽 :使用
redis-cli --cluster reshard手动重新分配哈希槽,将压力大的节点的槽迁移到压力小的节点; - 动态扩容:添加新的 Redis 节点,将现有节点的槽迁移到新节点,分散负载。
六、运维监控类问题
Redis 的运维监控是保障服务稳定的关键,若缺乏有效的监控和规范的运维操作,会导致问题无法及时发现、故障扩大化。
1. 缺乏监控,问题发生后无法快速定位
问题表现:Redis 出现性能问题、宕机后,无法快速获取 CPU、内存、QPS、延迟、连接数等指标,定位问题耗时过长。
核心原因:未搭建 Redis 监控体系,仅依赖人工排查。
解决方案:
- 基础监控 :使用 Redis 自带的
info、slowlog、client list、dbsize等命令,定期采集指标; - 开源监控工具 :搭建Prometheus + Grafana 监控体系,结合
redis_exporter采集 Redis 指标,配置可视化仪表盘,监控核心指标(内存使用、QPS、延迟、连接数、主从同步状态、集群槽状态); - 告警配置:对核心指标设置告警阈值(如内存使用率 > 80%、QPS 骤降 50%、延迟 > 1ms、连接数 > maxclients*80%),通过邮件、钉钉、企业微信等方式推送告警;
- 日志收集:收集 Redis 的慢查询日志、启动日志、持久化日志,使用 ELK/PLG 栈做日志分析,定位问题。
2. 内存满了,Redis 出现数据淘汰 / 阻塞
问题表现 :Redis 内存使用率达到maxmemory,触发数据淘汰策略,部分键被删除,或因淘汰数据占用单线程资源导致阻塞。
核心原因:
未设置maxmemory,Redis 占用内存超过物理内存,触发 swap;
maxmemory设置过小,或数据量增长过快,导致内存占满;
淘汰策略配置不合理(如 noeviction 不淘汰任何数据,直接拒绝写请求)。
解决方案:
1.临时解决 :增大maxmemory,或手动删除冷数据 / 大键,释放内存;
2.配置合理的淘汰策略:根据业务场景选择淘汰策略,Redis 共提供 8 种淘汰策略,常用的有:
volatile-lru:淘汰设置了过期时间的键中,最近最少使用的(推荐缓存场景);allkeys-lru:淘汰所有键中最近最少使用的(适用于纯缓存,无过期时间);volatile-ttl:淘汰设置了过期时间的键中,剩余过期时间最短的;- 禁止使用
noeviction(生产环境),否则内存满后会拒绝所有写请求;
3.长期优化:
- 做 Redis集群分片,将数据分散到多个节点,提升整体内存容量;
- 定期清理冷数据、过期数据,避免内存堆积;
- 对大键做分桶,减少单键内存占用。
3. 生产环境直接执行危险命令,导致数据丢失 / 服务异常
问题表现 :人工误执行FLUSHDB/FLUSHALL(清空数据库)、CONFIG SET(修改配置)、DEL(删除核心键)等危险命令,导致数据丢失、服务异常。
核心原因 :生产环境 Redis 未做命令权限控制,允许任意客户端执行危险命令。
解决方案:
-
重命名危险命令:在redis.conf中通过 rename-command 重命名危险命令,甚至禁用,如:
plaintextrename-command FLUSHDB "" # 禁用FLUSHDB rename-command FLUSHALL "" # 禁用FLUSHALL rename-command DEL REDIS_DEL_123456 # 重命名DEL为随机字符串 -
设置 Redis 密码 :生产环境必须设置复杂的密码(
requirepass),避免未授权访问; -
网络访问控制 :通过防火墙 / 安全组限制 Redis 的访问 IP,仅允许应用服务器、监控服务器访问 Redis 端口(6379),禁止公网访问;
-
操作规范 :生产环境执行 Redis 命令需走审批流程,禁止直接在生产节点执行危险命令,可通过只读从节点做查询排查。
七、Redis 常见问题排查思路总结
当 Redis 出现问题时,遵循从现象到本质,从基础到复杂的排查思路,快速定位问题:
- 查看应用侧报错:确定是连接问题、命令执行失败、超时还是数据问题;
- 检查 Redis 进程状态 :
ps -ef | grep redis,确认 Redis 是否运行,端口是否监听(netstat -tulpn | grep 6379); - 查看 Redis 日志 :Redis 的日志文件(默认
redis-server.log)会记录启动、持久化、主从同步、集群、错误等信息,是排查问题的核心; - 采集 Redis 核心指标 :通过
redis-cli info采集内存、CPU、连接数、QPS、主从同步、持久化等指标,定位瓶颈; - 排查慢查询 :
slowlog get定位慢命令,排查单线程阻塞; - 排查客户端连接 :
client list查看连接数、空闲连接、阻塞连接,排查连接泄漏 / 耗尽; - 检查服务器资源 :
top(CPU / 内存)、iftop(网络)、iostat(磁盘 IO)、free -m(内存 /swap),排查硬件 / 系统瓶颈。
八、Redis 生产环境实践总结
- 部署规范:物理机部署,主从 / 集群同机房同网段,避免跨机房;禁用透明大页,优化网络 / 磁盘配置;
- 配置规范 :开启持久化(RDB+AOF 混合),设置合理的
maxmemory和淘汰策略;重命名 / 禁用危险命令,设置密码和 IP 白名单;开启慢查询日志,配置连接超时; - 开发规范 :避免大键 / 热键,使用分桶 / 分片;用分段命令替代全量操作,
UNLINK替代DEL;使用连接池,避免连接泄漏;缓存层做穿透 / 击穿 / 雪崩防护; - 高可用规范:主从复制至少一主一从,哨兵集群至少 3 个节点,Redis Cluster 主节点数为奇数;
- 监控告警:搭建 Prometheus+Grafana 监控,配置核心指标告警,收集日志并做分析;
- 运维规范:定期备份持久化文件,定期检测大键 / 慢查询;禁止生产环境直接执行危险命令,操作走审批;定期做故障演练(如主节点宕机、故障切换)。