2-2-3-1-分布式缓存
1、分布式缓存总结与核心内容
分布式缓存是高并发系统的核心组件,用于缓解数据库压力、提升读取性能。其考察内容既覆盖底层原理(如Redis持久化、内存管理),也涉及工程实践(如一致性解决、热点处理),更关联分布式系统设计(如分片、容错)。以下是结构化的考察点拆解,结合原理、实践与面试追问:
一、分布式缓存基础概念与定位
1. 核心价值
- 性能提升:缓存命中率可达80%-99%,将数据库QPS从1万降至100以内;
- 压力分流:避免数据库成为“单点瓶颈”;
- 用户体验:响应时间从百ms级降至ms级(如Redis读取约100μs)。
2. 定位边界
- 适合缓存:高频读、低频写、非强一致性数据(如商品详情、用户信息);
- 不适合缓存:频繁写(如实时计数器)、强一致性(如银行转账)、大key(如100MB的视频)。
二、常用分布式缓存产品对比
面试常考选型依据,需明确不同产品的优缺点与适用场景:
| 维度 | Redis | Memcached | Ehcache |
|---|---|---|---|
| 数据结构 | 支持String/Hash/List/Set/SortedSet等 | 仅字符串 | 支持多种(类似Redis,但本地) |
| 分布式模型 | 主从/哨兵/Cluster(分布式) | 客户端分片 | 本地缓存(可结合Terracotta做分布式) |
| 持久化 | RDB+AOF(支持混合) | 无 | 支持磁盘持久化 |
| 内存管理 | 内置LRU/LFU/TTL淘汰策略 | LRU | 自定义淘汰策略 |
| 性能 | 单线程IO多线程(6.0+),QPS≈10万 | 多线程,QPS≈10万 | 本地调用,QPS≈100万 |
| 适用场景 | 分布式系统、复杂数据结构、高可用需求 | 简单key-value、高并发读 | 本地缓存、低延迟 |
面试追问:为什么Redis能替代Memcached成为主流?
答:Redis的数据结构多样性(如Sorted Set做排行榜、Hash存对象)、持久化能力(避免重启丢数据)、分布式支持(Cluster模式横向扩容)是核心优势。
三、核心原理深度解析
1. Redis持久化:数据安全的基石
持久化解决缓存宕机后数据恢复问题,需理解两种模式的原理与权衡:
(1)RDB(快照持久化)
- 原理:定时(如每5分钟)将内存数据快照写入二进制文件(dump.rdb);
- 触发方式:手动
SAVE/BGSAVE(后台fork子进程)、自动配置; - 优点:文件小(压缩)、恢复快(直接加载快照);
- 缺点:可能丢数据(如宕机前未触发快照);
- 工程实践:生产环境很少单独用RDB,通常配合AOF。
(2)AOF(追加日志持久化)
- 原理:记录所有写操作命令(如
SET key value),以文本形式追加到文件(appendonly.aof); - 同步策略:
always:每条命令同步刷盘(数据安全,性能差);everysec:每秒刷盘(默认,平衡安全与性能);no:由操作系统决定(性能好,数据风险高);
- 重写机制:AOF文件过大时,自动合并重复命令(如多次
INCR合并为SET); - 优点:数据安全性高(最多丢1秒数据);
- 缺点:文件大、恢复慢(需重放所有命令)。
(3)混合持久化(Redis 4.0+)
- 原理:AOF文件前半部分是RDB快照,后半部分是增量命令;
- 优势:兼顾RDB的快速恢复与AOF的数据安全。
面试追问:如果Redis宕机,如何选择持久化策略?
答:电商系统(如库存)选everysec+混合持久化;日志系统(允许丢数据)选RDB。
2. Redis内存管理:避免OOM的关键
Redis的内存限制(通过maxmemory配置)是分布式缓存的核心约束,需理解淘汰策略:
(1)淘汰策略分类
Redis的淘汰策略基于key的过期状态与访问频率:
- volatile-*:仅淘汰有过期时间的key;
- allkeys-*:淘汰所有key;
- lru/lfu:基于最近最少使用/最不经常使用;
- ttl:淘汰剩余过期时间最短的key;
- random:随机淘汰。
(2)工程选型建议
- 若缓存数据均有过期时间:选
allkeys-lru(优先淘汰最久未用的过期key); - 若缓存数据部分有过期时间:选
volatile-lru+allkeys-lru组合(需测试); - 若需保留热点数据:选
allkeys-lfu(更精准识别高频key)。
(3)LRU算法的Redis实现
- 传统LRU:用双向链表维护访问顺序,每次访问将节点移到链表头部,淘汰尾部节点;
- Redis LRU:近似实现(节省内存)——每个key额外存储一个
24位时钟(记录最后访问时间),淘汰时随机采样5个key,淘汰时钟最旧的。
面试追问:为什么Redis不用严格LRU?
答:严格LRU需要维护完整链表,内存开销大;近似LRU牺牲少量准确性,换取内存效率,符合Redis的轻量化设计。
3. Redis分布式模型:从主从到Cluster
分布式缓存的核心是横向扩容与高可用,Redis的三种分布式模式需深入理解:
(1)主从复制(Master-Slave)
- 原理:Slave节点复制Master的日志(RDB+AOF),实现数据同步;
- 作用:读写分离(Master写、Slave读)、数据备份;
- 问题:Master宕机后需手动切换,无自动容错。
(2)哨兵(Sentinel)
- 原理:多个Sentinel节点监控Master/Slave状态,当Master宕机时,自动选举新的Master并调整Slave指向;
- 核心功能:监控(Monitoring)、通知(Notification)、自动故障转移(Automatic Failover);
- 工程实践:至少部署3个Sentinel节点(避免脑裂)。
(3)Cluster(集群)
- 原理:将数据分片(Sharding)到多个节点,每个节点负责一部分槽位(共16384个槽);
- 分片方式:通过
CRC16(key) % 16384计算key所属槽位; - 高可用:每个节点有主从,主节点宕机后从节点晋升为主节点;
- 访问方式:客户端需支持Cluster协议(如JedisCluster),自动路由到对应槽位的节点。
面试追问:Redis Cluster扩容时需要注意什么?
答:1. 新增节点后,需用redis-cli --cluster reshard重新分配槽位;2. 避免大key迁移(会导致节点阻塞);3. 迁移过程中需监控命中率(避免缓存失效)。
四、分布式场景下的关键问题与解决
1. 缓存穿透(Cache Penetration)
- 定义:查询不存在的key,导致请求直接打到数据库(如查询不存在的用户ID);
- 危害:数据库压力骤增,甚至宕机;
- 解决方案:
- 布隆过滤器(Bloom Filter):在缓存前加布隆过滤器,判断key是否存在——不存在直接返回,避免查数据库;
- 缺点:有误判率(可通过增加哈希函数数量降低),需定期重建;
- Null缓存:若查询数据库不存在,缓存一个
null值(设置短过期时间,如1分钟); - 参数校验:前端/接口层校验key的合法性(如用户ID必须为正整数)。
- 布隆过滤器(Bloom Filter):在缓存前加布隆过滤器,判断key是否存在——不存在直接返回,避免查数据库;
面试追问:布隆过滤器的误判率怎么计算?
答:误判率≈(1 - e^(-kn/m))^k,其中k是哈希函数数量,n是已插入元素数,m是布隆过滤器大小。
2. 缓存击穿(Cache Breakdown)
-
定义:热点key过期瞬间,大量请求同时查询该key,导致请求打到数据库;
-
危害:数据库瞬时压力过大;
-
解决方案:
-
热点key永不过期:后台任务定期更新缓存(如秒杀商品的库存缓存);
-
分布式锁:用Redis的
SETNX或Redisson实现分布式锁,保证只有一个请求查数据库,其他请求等待缓存更新;-
示例代码(Redisson):
RLock lock = redisson.getLock("product:stock:lock"); try { if (lock.tryLock(0, 10, TimeUnit.SECONDS)) { // 尝试加锁,超时10秒 // 查数据库更新缓存 Product product = productDao.getById(id); redisTemplate.opsForValue().set("product:" + id, product, 1, TimeUnit.HOURS); } } finally { lock.unlock(); }
-
-
提前更新:通过消息队列(如Kafka)发送key过期通知,提前更新缓存。
-
面试追问:分布式锁的过期时间怎么设置?
答:需大于查询数据库+更新缓存的时间(如10秒),避免锁提前释放导致并发问题;同时用“看门狗”机制(Redisson默认)自动续期。
3. 缓存雪崩(Cache Avalanche)
- 定义:大量缓存同时过期,导致请求全部打到数据库;
- 危害:数据库宕机,系统不可用;
- 解决方案:
- 随机过期时间:给缓存设置不同的过期时间(如基础时间+随机1-5分钟);
- 多级缓存:本地缓存(如Guava Cache)+ Redis缓存——Redis失效后,本地缓存仍有数据;
- 熔断降级:用Sentinel/Hystrix设置数据库的熔断规则(如QPS超过100则熔断,返回默认值)。
4. 缓存一致性(Cache Consistency)
- 定义:数据库与缓存数据不一致(如更新数据库后,缓存未更新);
- 常见场景:Cache-Aside模式下,更新数据库后,缓存未删除;
- 解决方案:
- Cache-Aside(旁路缓存):最常用,但需严格遵循规则:
- 读:先读缓存→无则读数据库→更新缓存;
- 写:先更新数据库→删除缓存(而非更新缓存,避免并发问题);
- 延迟双删:更新数据库后,先删除缓存,再延迟1-2秒再次删除(解决“写后读不一致”);
- 消息队列异步更新:更新数据库后,发送消息到Kafka,消费者更新缓存(保证最终一致性);
- 分布式事务:用Seata做分布式事务,同时更新数据库与缓存(强一致性,性能差)。
- Cache-Aside(旁路缓存):最常用,但需严格遵循规则:
面试追问:为什么Cache-Aside模式要“先更库再删缓存”,而不是“先删缓存再更库”?
答:若先删缓存,再更库,此时另一个请求读缓存→未命中→读数据库(旧值)→更新缓存(旧值),导致缓存中还是旧值。而先更库再删缓存,即使有并发读,最终缓存会被删除,下次读取会拿到新值。
五、工程实践细节与最佳实践
1. 缓存预热(Cache Warm-Up)
- 定义:系统启动时,将热点数据加载到缓存;
- 场景:电商大促前(如双11前加载热门商品缓存);
- 实现:用定时任务(如Quartz)或启动脚本加载数据。
2. 大key处理
- 定义:单个key的value过大(如>10KB);
- 危害:查询慢、迁移阻塞、内存分配不均;
- 解决方案:
- 拆分key:将大Hash拆分为多个小Hash(如
user:info:123→user:info:123:base+user:info:123:ext); - 使用SCAN命令:避免用
KEYS命令遍历大key(会导致阻塞); - 限制value大小:通过程序校验,禁止存入超过100KB的value。
- 拆分key:将大Hash拆分为多个小Hash(如
3. 监控与运维
- 关键指标:
- 命中率(Hit Rate):
hit / (hit + miss),低于80%需排查; - 内存使用率:超过90%需扩容;
- QPS:超过峰值需限流;
- 命中率(Hit Rate):
- 工具:
- Redis自带的
INFO命令(查看状态); - Prometheus+Grafana(监控可视化);
- RedisInsight(GUI工具,排查问题)。
- Redis自带的
4. 最佳实践
- key命名规范:用业务前缀+唯一标识(如
order:info:123),方便管理与排查; - 避免复杂操作:不用
KEYS、FLUSHALL等危险命令; - 设置合理过期时间:根据业务场景设置(如用户信息缓存1小时,商品详情缓存30分钟);
- 使用连接池:避免频繁创建连接(如JedisPool)。
六、与其他组件的整合
1. 与数据库整合
- 读流程:Cache-Aside→读缓存→无则读数据库→更新缓存;
- 写流程:先更库→删缓存(或异步更新缓存);
- 事务配合:若写数据库失败,需回滚缓存的删除操作(或用消息队列重试)。
2. 与消息队列整合
- 缓存失效通知:缓存过期时,发送消息到Kafka,消费者更新缓存;
- 异步更新缓存:更新数据库后,发送消息,消费者异步更新缓存(减少数据库压力)。
3. 与分布式锁整合
- 解决缓存击穿:热点key过期时,用分布式锁保证只有一个请求查数据库;
- 解决并发更新:多个请求同时更新缓存时,用锁保证原子性。
面试模拟:从问题到追问
面试官:如果让你设计一个电商系统的商品详情缓存,你会考虑哪些点?
候选人:首先,用Redis做分布式缓存,key用product:info:{id},value存商品对象(Hash结构);然后,设置过期时间(如30分钟),避免缓存永久有效;接着,处理缓存穿透——用布隆过滤器判断商品ID是否存在;处理缓存击穿——热点商品(如秒杀商品)永不过期,用Redisson分布式锁防止并发查数据库;处理缓存雪崩——给过期时间加随机1-5分钟;最后,监控命中率,低于80%时排查问题。
面试官追问:布隆过滤器的误判率怎么处理?
候选人:可以增加布隆过滤器的大小(m),或者定期重建布隆过滤器(如每小时重建一次)。
面试官追问:如果Redis Cluster扩容,如何保证缓存命中率?
候选人:扩容时用redis-cli --cluster reshard重新分配槽位,尽量减少数据迁移;迁移过程中,监控命中率,若下降明显,暂停迁移并优化。
总结:分布式缓存的核心能力要求
- 原理层面:理解Redis的持久化、内存管理、分布式模型;
- 实践层面:能解决穿透/击穿/雪崩、一致性等问题;
- 设计层面:能结合业务场景设计缓存方案(如电商、社交);
- 运维层面:能监控、调优、扩容缓存集群。
掌握这些知识点,不仅能应对面试,更能解决实际系统中的缓存问题,成为资深架构师的核心竞争力。
2、Redis知识梳理
详见《5-2-3-组件选型》中Redis相关内容。
本文来自博客园,作者:哈罗·沃德,转载请注明原文链接:https://www.cnblogs.com/panhua/p/19210169
浙公网安备 33010602011771号