Redis 常见问题怎么排查?大 Key、热点和一致性如何处理?
Redis 常见问题不要按概念清单排查,线上通常先看现象:延迟升高、内存暴涨、从库追不上、数据库被打穿、某个接口 QPS 异常。高频原因包括大 Key、热点 Key、慢命令、缓存一致性、分布式锁误用和限流算法选错。Redis 很快,但单个大对象、阻塞命令、网络抖动和错误过期策略,都会把系统拖慢。
追问
Redis 为什么快,慢请求先看什么?
Redis 快在内存访问、单线程命令执行避免锁竞争、I/O 多路复用处理连接,以及高效数据结构。Redis 6 之后网络 I/O 可以多线程,但命令执行仍是核心单线程路径,一个慢命令会拖住后面的请求。排查先看 SLOWLOG GET、INFO commandstats、LATENCY DOCTOR,不要只盯 CPU;很多延迟其实来自阻塞命令、fork、AOF fsync、主从同步或客户端连接池耗尽。
大 Key 怎么发现,为什么不能直接 DEL?
大 Key 可能是几 MB 的字符串,也可能是几十万元素的 hash、list、set,可以用 redis-cli --bigkeys 抽样扫描,并在业务侧记录 value 大小。生产环境不要随手 KEYS *,它本身就可能阻塞实例。大 Key 的读写、序列化、网络传输和删除都可能卡主线程;删除时优先用 UNLINK 或后台渐进清理,核心集群要放在低峰并评估影响。
热点 Key 如何处理,复制多份一定安全吗?
热点 Key 是某个 key 被大量并发访问,常见于秒杀库存、首页配置、热门商品详情。只读热点可以用本地缓存、读写分离、客户端缓存,或复制多份 key 随机读取。写热点不能简单复制,否则一致性会很难保证;可累加计数可以分片后异步汇总,强一致库存更适合排队、限流或业务层削峰。
缓存和数据库不一致怎么处理?
常用 Cache Aside 是读缓存,未命中查数据库再写缓存;写数据时先更新数据库,再删除缓存。它简单可靠,适合大多数最终一致场景,但并发读写下仍可能短暂不一致。延迟双删能降低概率却不好选延迟时间,binlog 或消息队列更稳但链路更复杂;余额、库存扣减这类强一致路径不要依赖缓存读。
分布式锁和限流最容易踩哪些坑?
Redis 锁至少要用 SET key value NX EX seconds,释放时用 Lua 先比较 value 再删除,避免删掉别人的锁。过期时间太短会导致业务没跑完锁已释放,太长又影响故障恢复,Redisson 看门狗能缓解但不能无视 GC 暂停和网络分区。限流里固定窗口简单但有边界突刺,滑动窗口更平滑但占内存,令牌桶适合允许短时突发;无论哪种都要配合幂等和降级。
写段命令和配置
bashredis-cli SLOWLOG GET 10 redis-cli --latency -h 127.0.0.1 -p 6379 redis-cli LATENCY DOCTOR redis-cli --bigkeys redis-cli INFO memory redis-cli INFO commandstats
java// 安全释放分布式锁:比较 value 后再删除 String lua = "if redis.call('GET', KEYS[1]) == ARGV[1] " + "then return redis.call('DEL', KEYS[1]) else return 0 end"; redis.eval(lua, Collections.singletonList(lockKey), Collections.singletonList(lockValue));
java// Cache Aside:先更新数据库,再删除缓存 public void updateUser(User user) { db.update(user); redis.del("user:" + user.getId()); }
小结
Redis 排查要从现象回到机制:慢请求看阻塞和慢命令,内存问题看大 Key 和淘汰策略,流量尖峰看热点 Key,数据异常看缓存一致性链路。解决方案都在性能、一致性、复杂度之间取舍,提前做好 key 规模约束、慢日志监控、过期时间打散和降级预案,比报警后临时救火可靠。