分布式缓存策略的核心是结合业务场景选择缓存模式、淘汰算法和高可用方案,Redis凭借丰富的数据结构与集群能力成为主流实现。
Redis缓存策略有哪些?核心机制与选型指南
理解Redis缓存策略,本质上是回答“缓存什么、存多久、满了怎么办”这三个问题,业内常见的策略体系围绕缓存模式、淘汰算法和过期策略展开,每个维度都直接影响系统性能与数据一致性。
缓存模式与业务匹配
- Cache Aside(旁路缓存):最常用的模式,业务代码同时维护缓存和数据库,读时先查缓存,命中则返回;未命中则查数据库,回填缓存,写时更新数据库,随后删除缓存,这种模式适合读多写少、对一致性要求不高的场景,如商品详情页。
- Read/Write Through(读写穿透):缓存层负责与数据库交互,应用只与缓存通信,读未命中时由缓存组件从数据库加载,写时由缓存同步写入数据库,该模式简化了业务代码,但只适合缓存层具备完整数据源能力的场景,如本地缓存库。
- Write Behind(异步写回):写操作仅更新缓存,异步批量写入数据库,性能极高,但可能丢数据,适用于日志、点赞等弱一致性场景。
选择建议:互联网业务首选Cache Aside,因为其代码逻辑清晰,结合Redis的原子操作可避免并发写冲突,若需强一致性,可搭配分布式锁。
缓存淘汰策略详解
当内存写满时,Redis根据配置的maxmemory-policy决定淘汰哪些键,常见策略包括:
- LRU(最近最少使用):淘汰最近最久未使用的键。
allkeys-lru对所有键生效,volatile-lru仅对带过期时间的键生效,多数场景下推荐allkeys-lru,因为它能自适应访问模式,比如热点商品数据自然保留,冷数据被淘汰。 - LFU(最不经常使用):淘汰访问频率最低的键。
allkeys-lfu和volatile-lfu对应,适用于访问模式有冷热分明的业务,如某段时间内用户频繁访问某个活动页面,活动结束后访问骤降,LFU能更快识别并淘汰。 - TTL(即将过期):淘汰剩余存活时间最短的键。
volatile-ttl仅对设置了过期时间的键有效,适合需要精确控制过期顺序的场景,如会话缓存。 - 随机淘汰:
allkeys-random和volatile-random,用于临时缓存或请求量极低的场景,一般不用。
实操步骤

:在redis.conf中设置maxmemory 4gb和maxmemory-policy allkeys-lru,然后重启Redis或执行CONFIG SET maxmemory-policy allkeys-lru动态生效,建议根据业务流量估算内存上限,保留20%冗余。
过期策略与内存管理
Redis采用定期删除+惰性删除组合,定期删除每隔100ms随机抽取部分带过期时间的键检查并删除;惰性删除在每次访问键时检查是否过期,过期则删除,这种策略避免了全量扫描的性能开销,但会导致过期键在未被访问时残留占用内存,合理设置maxmemory和淘汰策略是内存管理的最后防线。
小技巧:对于大量相同过期时间的键,可以给它们增加随机偏移量,避免同一时间大量键过期导致缓存雪崩,例如在设置缓存时,过期时间统一为“3600 + random(0,600)”。
Redis缓存穿透解决方案:布隆过滤器与缓存空对象
缓存穿透是指查询一个不存在的数据,由于缓存未命中,每次请求都落到数据库,导致数据库压力飙升,常见于恶意攻击或查询不存在的ID场景。
缓存穿透成因与影响
当API接口未对参数做校验,或者用户按顺序遍历ID时,大量请求直接穿透缓存,例如一个电商系统,用户请求商品ID为“-1”或一个不存在的ID,如果缓存层未命中,数据库每次都要返回空结果,大量并发下数据库连接可能被耗尽。
布隆过滤器实现步骤
布隆过滤器是一种概率型数据结构,用于判断元素是否“可能存在”或“肯定不存在”,使用多个哈希函数将元素映射到一个位数组中,存在误判率(可能把不存在判为存在),但不会漏判。
实现步骤:
- 预估容量和误判率:假设预计存储100万个key,允许误判率1%,则位数组长度约1200万bit,哈希函数数量约7个。
- 初始化位数组:在Redis中,可以使用
SETBIT命令操作字符串实现位数组,或使用Redis 4.0+的BF.RESERVE模块命令,推荐使用Redisson或Lettuce等客户端内置布隆过滤器。 - 预热数据:将所有可能存在的key(如商品ID)提前写入布隆过滤器。
- 查询流程:请求到达时,先检查布隆过滤器,如果过滤器返回不存在,直接拒绝请求;如果返回可能存在,再查询缓存或数据库。
代码示例(Java + Redisson):
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("productFilter");
bloomFilter.tryInit(1000000L, 0.01);
// 预热
bloomFilter.add("123");
// 查询
if (!bloomFilter.contains(requestId)) {
return "不存在";
}

注意:布隆过滤器无法删除元素,如果业务数据频繁删除,考虑使用布隆过滤器的变种(如Counting Bloom Filter)或定期重建。
缓存空对象与降级策略
当查询结果为空时,将空结果也缓存起来,设置较短的过期时间(如60秒),这样后续相同请求可以从缓存中拿到空值,避免穿透,缺点是缓存层会存储大量空键,占用内存,且可能导致数据不一致(如果真实数据写入后,空缓存未过期),解决方案是结合布隆过滤器使用,布隆过滤器拦截大部分不存在请求,缓存空对象作为兜底。
降级策略:在缓存层与数据库之间增加限流组件,如Sentinel或Hystrix,当数据库压力超过阈值时,直接返回默认值或错误提示,保护数据库。
高并发场景下Redis缓存策略实战
高并发场景对缓存策略的挑战来自热点key、缓存雪崩和集群扩展,业界在实践中总结出若干可复用的方案。
热点key的发现与处理
热点key指短时间内被大量访问的key,比如明星动态、秒杀商品,它们会导致Redis单实例CPU飙升,甚至引发局部故障。
发现方法:本地统计访问频率,在Redis客户端使用INFO commandstats查看命令频次,或使用Redis 6.0的CLIENT LIST结合idle字段监测,开源工具如RedisHotKey也能实时监控。
处理方案:
- 本地缓存+Redis缓存:在应用层使用Caffeine或Guava Cache缓存热点key,设置较短的过期时间(如1秒),减少对Redis的请求。
- 读写分离:让热key的读请求分散到多个Redis从节点,或使用Redis Cluster自然分片。
- 限流与降级:对热点key的写操作进行限流,读操作返回过期数据或默认值。
缓存雪崩预防与互斥锁
缓存雪崩指大量缓存key在同一时间过期,或Redis实例宕机,导致所有请求直接打到数据库,预防措施包括:
- 过期时间加随机值:避免大批key同时过期,设置过期时间时增加随机偏移量。
- 高可用架构:使用Redis Sentinel或Cluster保证故障自动切换,防止单点失效。
- 互斥锁(Mutex):当缓存失效时,只允许一个线程去加载数据,其他线程等待或返回旧缓存,实现方式:使用
SETNX命令尝试获取锁,成功则加载数据,其他线程后重试。
sleep
实操步骤:在Java中,使用Redisson的RLock实现:
RLock lock = redisson.getLock("cache_rebuild_lock");
if (lock.tryLock(100, 10, TimeUnit.SECONDS)) {
try {
// 查询数据库并回填缓存
} finally {
lock.unlock();
}
} else {
// 等待或返回旧值
}
集群高可用方案对比
Redis高可用方案主要有哨兵模式和集群模式。
| 方案 | 架构 | 优点 | 适用场景 |
|---|---|---|---|
| 哨兵模式 | 一主多从,哨兵监控 | 配置简单,自动故障转移 | 数据量不超过单机内存,读写分离需求 |
| 集群模式 | 多主多从,数据分片 | 容量水平扩展,自动分片 | 数据量超过单机内存,高并发写入 |
选择建议:数据量在10GB以内且对一致性要求高的场景,优先使用哨兵模式;数据量达到百GB级或需要弹性伸缩时,选择集群模式,国内云厂商提供的Redis服务(如简米云、酷番云)通常支持两种模式,价格差异主要体现在规格和带宽上,企业版价格通常比自建高30-50%,但免运维。
分布式缓存(Redis)常见问题解答
Q1: Redis缓存穿透和缓存雪崩有什么区别?
缓存穿透是查询不存在的数据,每次绕过缓存直达数据库;缓存雪崩是大量缓存key同时失效或Redis宕机,导致请求全部落到数据库,前者是数据缺失,后者是缓存失效,解决方案不同:穿透用布隆过滤器和空对象缓存,雪崩用过期时间随机化和高可用集群。
Q2: 如何选择合适的Redis缓存淘汰策略?
多数场景推荐allkeys-lru,因为它能自动保留热点数据,如果业务访问模式有明确冷热周期,且对最近访问不敏感,可选allkeys-lfu,如果每个key都有明确的过期时间且希望优先淘汰即将过期的key,可选volatile-ttl,优先保障内存不溢出,再根据业务验证响应时间。
Q3: Redis集群模式下缓存策略有何变化?
集群模式下,key根据哈希槽分布到不同节点,淘汰策略、过期策略在每个节点独立执行。缓存穿透和雪崩的解决方案不变,但热点key可能导致单个节点压力过大,需结合本地缓存或一致性哈希优化,布隆过滤器建议在客户端侧维护,避免跨节点请求。