面试题答案
一键面试解决缓存雪崩问题
- 设置不同过期时间:
- 避免大量缓存同时过期。对不同的用户动态数据设置一个随机的过期时间范围,例如原本过期时间是60分钟,可以设置为50 - 70分钟之间的随机值。这样即使有大量缓存数据同时创建,也不会在同一时间过期,从而降低缓存雪崩的风险。
- 二级缓存:
- 可以使用两级缓存结构,一级缓存使用内存占用小、读写速度极快的如
TinyLFU
算法实现的缓存,二级缓存使用普通的Redis缓存。当一级缓存未命中时,再访问二级缓存。如果二级缓存也未命中,才查询数据库。这样在一级缓存失效时,二级缓存能起到一定的缓冲作用,减轻数据库压力。
- 可以使用两级缓存结构,一级缓存使用内存占用小、读写速度极快的如
- 缓存永不过期:
- 对于一些非常重要且不经常变化的数据(如社交媒体平台中某些基本配置信息等),可以设置缓存永不过期。定期在后台使用异步任务去更新这些缓存数据,确保数据的一致性。
解决缓存击穿问题
- 互斥锁:
- 当缓存失效时,在查询数据库之前,先获取一个互斥锁(例如使用
SETNX
命令在Redis中创建一个临时锁)。只有获取到锁的线程可以查询数据库并更新缓存,其他线程等待。当获取锁的线程完成数据库查询和缓存更新后,释放锁,其他等待的线程再尝试获取锁并检查缓存是否已更新,若已更新则直接从缓存获取数据。
- 当缓存失效时,在查询数据库之前,先获取一个互斥锁(例如使用
- 热点数据不过期:
- 对于社交媒体平台中频繁访问的热点用户动态数据(如明星发布的动态等),设置缓存不过期。同时使用一个后台线程定期更新这些热点数据的缓存,确保数据的及时性和一致性。
保证缓存与MySQL数据一致性
- 读写操作顺序:
- 写操作:先更新MySQL数据库,成功后再删除Redis缓存。这样在下次读取数据时,由于缓存已删除,会重新从数据库读取并更新缓存,保证数据一致性。例如在用户发布新动态时,先将动态数据写入MySQL,成功后删除对应缓存。
- 读操作:先从Redis缓存读取数据,如果缓存命中则直接返回;若未命中,从MySQL读取数据,然后将数据写入Redis缓存并返回。
- 使用消息队列(MQ):
- 在更新MySQL数据时,同时发送一条消息到MQ。由MQ的消费者负责删除Redis缓存。这样可以将缓存更新操作异步化,减少数据库操作的阻塞时间,同时保证数据一致性。例如在用户修改动态内容时,MySQL更新成功后,向MQ发送一条消息,MQ消费者接收到消息后删除Redis中对应的缓存数据。
根据业务特点动态调整缓存策略
- 数据访问频率分析:
- 通过分析日志或使用专门的监控工具,统计不同类型用户动态数据的访问频率。对于访问频率高的热门数据,适当延长缓存时间,或者采用热点数据不过期策略。对于访问频率低的冷门数据,可以缩短缓存时间,减少内存占用。
- 数据更新频率分析:
- 分析不同类型数据的更新频率。对于更新频繁的数据,如用户实时点赞数等,采用先更新数据库再删除缓存的策略,并适当缩短缓存时间,保证数据的及时性。对于更新不频繁的数据,如用户简介等,可以适当延长缓存时间。
- 业务高峰低谷分析:
- 在社交媒体平台业务高峰时段(如晚上用户活跃度高),为了防止缓存雪崩和击穿,进一步分散缓存过期时间,加强互斥锁等机制的使用。在业务低谷时段,可以适当调整缓存策略,例如进行缓存数据的全量或增量更新,优化缓存结构等,以提高系统整体性能。