面试题答案
一键面试缓存架构设计
- 选择合适的缓存类型
- 基于内存的缓存:如Redis,具有极高的读写速度,适合存储频繁访问且数据量相对较小但实时性要求高的数据,像用户登录状态、高频查询的配置信息等。
- 磁盘缓存:如果数据量较大且对读写速度要求不是极致高时,可考虑磁盘缓存,如DiskCache。它可以存储更多的数据,但读写速度相对内存缓存较慢。
- 缓存分层设计
- 一级缓存:采用本地缓存(如Python的
functools.lru_cache
),用于缓存函数级别的计算结果,在进程内快速响应请求,减少函数重复计算开销。适用于一些不常变化且计算复杂的函数结果缓存。 - 二级缓存:使用分布式缓存(如Redis集群),缓存跨进程共享的数据,像用户相关的全局信息、热门商品数据等。可应对高并发场景下不同进程对相同数据的访问需求。
- 一级缓存:采用本地缓存(如Python的
缓存粒度控制
- 数据粒度
- 细粒度缓存:对于经常变动的数据,采用细粒度缓存。例如,在电商项目中,商品的价格可能频繁变动,此时可以对每个商品的价格进行单独缓存。这样在价格变动时,只需要更新对应商品价格的缓存,而不影响其他缓存数据。
- 粗粒度缓存:对于相对稳定的数据,采用粗粒度缓存。比如,电商平台的首页展示信息,包括一些热门分类、推荐商品等,这些数据更新频率低,可以整体进行缓存,减少缓存管理开销。
- 缓存失效策略
- 定时失效:为缓存数据设置合理的过期时间。对于一些时效性较强的数据,如新闻资讯,设置较短的过期时间(如几分钟到几小时不等),确保数据的实时性。
- 基于事件的失效:当数据库中相关数据发生变化时,主动失效对应的缓存。例如,在数据库中更新了商品信息,同时发送消息通知缓存系统删除或更新对应的商品缓存数据。
与其他组件协同
- 与数据库协同
- 缓存预热:在项目启动时,从数据库加载一些热门数据到缓存中,避免用户首次访问时因缓存未命中而查询数据库带来的延迟。例如,加载热门商品信息到Redis缓存。
- 缓存更新策略:
- 先更新数据库,再更新缓存:这种方式简单直接,但在高并发场景下可能出现数据库更新成功而缓存更新失败的情况,导致数据不一致。
- 先删除缓存,再更新数据库:可避免上述问题,但可能会出现短暂的缓存穿透现象(查询不存在的数据,每次都查询数据库)。为防止缓存穿透,可在数据库查询结果为空时,将空结果也缓存起来并设置较短过期时间。
- 双写一致性方案:结合前两种方案,先删除缓存,更新数据库后,延迟一定时间再次检查缓存并更新,通过一定的延迟操作确保数据一致性。
- 与消息队列协同
- 异步缓存更新:当数据发生变化时,将缓存更新操作封装成消息发送到消息队列(如Kafka)。由消息队列消费者异步处理缓存更新,这样可避免在业务处理过程中直接更新缓存带来的性能损耗,提高系统整体的响应速度。例如,在订单创建成功后,将订单相关的缓存更新消息发送到消息队列。
- 缓存失效通知:通过消息队列广播缓存失效消息。当数据库中某些关键数据发生变化时,发送消息通知所有相关的服务节点,使它们能够及时更新或删除本地缓存,保证缓存数据的一致性。