面试题答案
一键面试基于多维度数据模型的缓存方案设计
- 按数据类型和访问模式分区缓存
- 用户资料:通常访问频率高且相对稳定,适合采用分布式缓存(如 Redis)。可以以用户 ID 为 key,将整个用户资料对象作为 value 进行缓存。考虑到可能有部分用户资料更新较为频繁(如头像、签名等),可以将这部分单独拆分缓存,设置较短的过期时间。
- 好友关系:访问模式可能是根据用户 ID 获取其好友列表。可以使用 Redis 的 Set 数据结构,以用户 ID 为 key,好友 ID 集合为 value 进行缓存。由于好友关系变动相对不频繁,缓存过期时间可设置较长。
- 动态信息:动态信息更新频率高且访问量大。可以按时间线维度进行缓存,例如,以用户 ID 和时间范围(如一天)为复合 key,缓存该用户在特定时间范围内发布的动态列表。同时,对于热门动态,可以额外设置全局缓存,以提高访问效率。
- 多级缓存架构
- 一级缓存:采用本地缓存(如 Guava Cache),部署在应用服务器本地。它的优点是访问速度极快,适合缓存近期频繁访问的数据。由于本地缓存容量有限,设置较小的缓存空间和较短的过期时间。
- 二级缓存:使用分布式缓存(如 Redis)作为二级缓存。它具有更大的存储容量和分布式特性,能应对大规模数据的缓存需求。一级缓存未命中时,才访问二级缓存。
高并发和数据一致性场景下的缓存系统优化
- 缓存淘汰算法的选择
- LRU(最近最少使用):适用于大部分数据的缓存淘汰。它基于访问时间来判断数据的活跃程度,将最近最少使用的数据淘汰。在 Redis 中,可以通过配置
maxmemory-policy volatile - lru
来启用针对设置了过期时间的 key 的 LRU 淘汰策略,或maxmemory-policy allkeys - lru
对所有 key 启用 LRU 淘汰策略。 - LFU(最不经常使用):对于一些长期访问频率较低但偶尔会被大量访问的数据,LFU 更为合适。它根据数据的访问频率来淘汰,Redis 4.0 后也提供了近似 LFU 策略(
maxmemory - policy volatile - lfu
和maxmemory - policy allkeys - lfu
)。
- LRU(最近最少使用):适用于大部分数据的缓存淘汰。它基于访问时间来判断数据的活跃程度,将最近最少使用的数据淘汰。在 Redis 中,可以通过配置
- 缓存穿透问题的解决策略
- 布隆过滤器:在查询数据前,先通过布隆过滤器判断数据是否存在。如果布隆过滤器判断不存在,则直接返回,避免查询数据库。布隆过滤器可以使用 Redis 的 BitMap 来实现,将所有可能存在的 key 提前通过哈希函数映射到 BitMap 中。
- 缓存空值:当查询数据库未命中时,将空值也缓存起来,并设置较短的过期时间。这样下次查询相同 key 时,直接从缓存获取空值,避免重复查询数据库。
- 缓存雪崩问题的解决策略
- 设置随机过期时间:避免大量 key 在同一时间过期。在设置缓存过期时间时,在一个基础时间上加上一个随机的时间偏移,使得 key 的过期时间分散。
- 分级缓存:如上述的多级缓存架构,一级缓存可以在二级缓存大量失效时起到一定的缓冲作用,减少对数据库的直接冲击。
- 互斥锁:在缓存失效时,使用互斥锁(如 Redis 的 SETNX 命令)保证只有一个线程去查询数据库并更新缓存,其他线程等待。这样可以避免大量线程同时查询数据库导致的性能问题。