面试题答案
一键面试1. 缓存失效总体处理思路
- 跨服务协同:当Redis某一层级缓存失效时,涉及到的微服务之间需要通过消息队列、事件总线等机制进行通信。例如,使用Kafka、RabbitMQ等消息队列,缓存失效的服务将失效信息发送到消息队列,其他相关服务订阅该队列,获取失效信息后采取相应操作。
- 跨数据库节点协同:在读写分离的MySQL集群中,写操作一般在主节点,读操作在从节点。当缓存失效需要从数据库获取数据时,要确保从节点数据的一致性。可以通过主从复制机制,确保主节点数据更新后及时同步到从节点。同时,对于一些关键数据的读取,可以暂时绕过从节点,直接从主节点读取,以保证数据的最新性。
2. 不同失效场景处理方案
缓存雪崩
- 场景描述:大量缓存同时失效,导致大量请求直接访问数据库,可能压垮数据库。
- 处理方案:
- 设置不同过期时间:在缓存写入时,为不同数据设置随机的过期时间,避免大量缓存同时过期。例如,原本过期时间为1小时的缓存,设置为50 - 70分钟之间的随机值。
- 兜底策略:使用Hystrix等熔断器框架,当数据库请求量达到一定阈值时,熔断器跳闸,返回兜底数据(如默认值、缓存中旧数据等),避免数据库被压垮。同时,记录请求日志,待系统恢复后重新处理这些请求。
- 预热缓存:在系统启动时,通过批量加载数据到缓存中,避免启动后短时间内大量缓存失效。可以使用定时任务定期更新缓存,确保缓存中的数据是最新的。
缓存穿透
- 场景描述:查询不存在的数据,每次都绕过缓存直接访问数据库,增加数据库压力。
- 处理方案:
- 布隆过滤器:在缓存之前增加布隆过滤器,将所有可能存在的数据哈希到一个足够大的位数组中。当查询数据时,先通过布隆过滤器判断数据是否存在,如果不存在则直接返回,不再访问数据库。例如,使用Google Guava库中的BloomFilter实现布隆过滤器。
- 空值缓存:当查询的数据在数据库中不存在时,也将该空值缓存起来,并设置较短的过期时间。下次查询同样的数据时,直接从缓存中获取空值,避免再次访问数据库。
缓存击穿
- 场景描述:热点数据缓存过期瞬间,大量请求同时访问数据库。
- 处理方案:
- 互斥锁:在缓存失效时,使用分布式锁(如Redis锁、Zookeeper锁)保证只有一个请求能从数据库加载数据并更新缓存,其他请求等待。例如,使用Redis的SETNX命令实现分布式锁。
- 二级缓存:对于热点数据,除了正常的缓存层级外,再设置一层本地缓存(如Guava Cache)。当一级缓存失效时,先从本地缓存获取数据,减轻数据库压力,同时异步更新一级缓存。