Redis 的高频痛点与挑战
使用 Redis 的过程中,挑战确实不少,而且它们往往不是来自 Redis 本身,而是源于使用方式、架构设计或运维管理上的疏忽,可以将这些挑战归纳为如下几个方面:
Hot Key 的挑战
- 找出HotKey:在业务低峰期用 redis-cli --hotkeys 来扫描分析。日常例行统计数据访问记录,统计访问频度较高的热点数据
- 缓存预热:在流量洪峰来临前(比如大促开始前)提前把热点数据加载到Redis中,避免瞬间的大流量击穿缓存
- 读写分离:如果热点主要是读请求,可以增加多个从节点,让读操作分散到各个从节点上,减轻主节点的压力
- 多份冗余:将同一个热点数据复制多份并存储在不同的Key里(例如 prd_123 复制为 prd_123_1、prd_123_2),让请求分散到不同的节点上
- 优化数据结构:若Set、ZSet集合元素过多则考虑将一个大Key拆分成多个小Key,避免单个Key过大引发的性能问题
- 设置合理的淘汰策略:对于有明显热点访问的场景,allkeys-lfu或volatile-lfu策略(优先淘汰访问频率低的数据)比传统的lru更合适
- 限流与熔断:对访问Redis的接口进行限流,当流量超过阈值时,直接拒绝部分请求或返回默认值,保护系统不被打垮
- 缓存击穿保护:当热点Key失效的瞬间,可能会有大量请求直接打到数据库。可以利用互斥锁,只允许一个请求去重建缓存,其他请求等待或返回旧数据。也可以配合布隆过滤器来拦截掉不存在的数据查询,防止缓存穿透。
Big Key 的挑战
- 找出BigKey:在业务低峰期用 redis-cli --bigkeys 统计每种数据类型的最大Key,不会阻塞主线程
- 大key拆分:将大Key分解为小Key
- 异步删除:使用 UNLINK 替代 DEL,它会将Key的释放操作交给后台线程处理,主线程立即返回,几乎不阻塞
注:删除一个巨大的Key会导致Redis主进程长时间阻塞
- 异步清空:使用 FLUSHALL ASYNC / FLUSHDB ASYNC 来异步清空数据库
- 惰性删除与过期策略优化:如果设置了过期时间,Redis默认在删除过期Key时也可能产生阻塞,建议修改 redis.conf 开启以下配置:
# 将过期Key的删除操作也改为后台异步
lazyfree-lazy-expire yes
lazyfree-lazy-eviction yes
lazyfree-lazy-server-del yes
replica-lazy-flush yes
- 对于无法避免的大Key,比如超过几十MB的纯数据,可以考虑压缩存储或将数据保存到对象存储(如S3、MinIO),Redis只存储其URL
- 总之:发现大Key用 --bigkeys,删除大Key用 UNLINK,根治大Key靠业务拆分
雪崩击穿穿透等挑战
- redis缓存使用中常见的问题:缓存雪崩、缓存击穿、缓存穿透,都会导致大量的请求直接访问数据库,造成数据库压力过大,甚至引起数据库崩溃的情况。
| 缓存问题 | 产生原因 | 解决方案 |
|---|---|---|
| 缓存雪崩 | 1.大量Key同时过期,DB压力骤增 2.缓存服务器宕机 |
对冷热数据设置不同的过期时间,或设置随机过期或永不过期 引入分布式缓存(比如Memcached),构建多级缓存 服务熔断机制,暂停对缓存服务的访问,直接返回错误 请求限流机制,只将部分请求发送到DB,再多请求直接拒绝 配置Redis哨兵或集群提高服务的可用性 |
| 缓存击穿 | 1.某个热点数据过期导致大量请求直达DB 2.访问到缓存中没有但数据库中有的数据 |
设置热点数据永远不过期 利用互斥锁(setnx方法)重建缓存,其他请求等待或返回旧数据 配合布隆过滤器来截绝大多数恶意或无效请求 |
| 缓存穿透 | 查不存在的数据,压力直达DB | 设置一个null值或者默认值,后续请求不再查询DB 使用布隆过滤器判断缓存是否存在(存在误判可能) |
| 缓存污染 | 缓存了大量冷数据导致真正热点的数据被淘汰出去 | 优化淘汰策略 |
- 缓存雪崩:当大量缓存数据在同一时间过期(失效)或者Redis 故障宕机时,如果此时有大量的用户请求,都无法在Redis中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩问题。
- 缓存击穿:如果缓存中某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库 ,数据库很容易被高并发的请求冲垮,这就是缓存击穿问题。
注:缓存击穿指的是大量并发查询同一条热点数据(Hot Key过期了),缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库
- 缓存穿透:当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据。那么此时大量的请求都落在数据库中,导致数据库压力骤增,这就是缓存穿透问题。
- 缓存污染:大量不常访问的数据被存入 Redis,挤占了宝贵的内存空间,导致真正热点的数据被淘汰出去
持久化的“双倍”内存开销
- 执行bgsave生成RDB快照时,依赖操作系统的fork()系统调用,会利用写时复制技术。这期间内存占用峰值可能达到原数据的两倍,必须预留充足的内存,否则fork失败将导致数据无法持久化
- 在 RDB(可能丢数据)和 AOF(影响性能)之间做权衡。推荐生产环境开启混合持久化,兼顾恢复速度和数据安全。
- 建议设置 maxmemory最大内存 + maxmemory-policy淘汰策略
解读:当redis内存数据达到maxmemory(建议设置为可用物理内存的40%)时,会根据maxmemory-policy配置来淘汰内存数据,以避免OOM。
如何保证缓存和数据库的一致性
- 待补充 ...

