MST

星途 面试题库

面试题:缓存设计之Redis内存优化的复杂场景应用

假设你负责一个大型电商系统的后端开发,其中商品详情页、购物车等功能广泛使用Redis作为缓存。该系统面临高并发读写,且内存资源有限。要求既要保证热门商品数据的快速访问,又要确保购物车操作的事务性和数据一致性。请设计一套完整的Redis内存管理与优化方案,包括数据结构选择、内存分配策略、缓存更新机制以及故障恢复策略等,并详细说明如何应对可能出现的缓存雪崩、缓存穿透和缓存击穿问题。
12.1万 热度难度
后端开发缓存设计

知识考点

AI 面试

面试题答案

一键面试

数据结构选择

  1. 商品详情页
    • 使用哈希(Hash)结构存储商品详情数据。例如,以商品ID为键,商品的各个属性(如名称、价格、描述等)作为哈希的字段和值。这样可以快速定位和获取特定商品的详细信息,且内存使用相对高效。例如:
    HSET product:1 name "手机"
    HSET product:1 price "2999"
    
  2. 购物车
    • 采用哈希结构存储购物车数据,以用户ID为键,购物车中的商品ID及对应数量作为哈希的字段和值。同时,可以结合有序集合(Sorted Set)来记录购物车操作的时间顺序(如果需要按操作时间处理一些事务逻辑)。例如:
    HSET cart:user1 product:1 2
    HSET cart:user1 product:2 1
    
    • 对于购物车事务,可以利用Redis的事务(MULTI/EXEC)功能,将多个购物车操作命令组合在一个事务中执行,保证数据一致性。

内存分配策略

  1. 配置Redis内存限制: 在Redis配置文件(redis.conf)中设置 maxmemory 参数,根据服务器实际可用内存,合理限制Redis使用的最大内存。例如:
    maxmemory 10gb
    
  2. 内存淘汰策略: 选择 allkeys - lru(最近最少使用)策略。此策略会在内存达到限制时,优先淘汰最近最少使用的键。这样可以保证热门商品数据能长时间保留在缓存中,提高缓存命中率。在Redis配置文件中设置:
    maxmemory - policy allkeys - lru
    

缓存更新机制

  1. 商品详情页
    • 采用写后更新策略。当商品数据在数据库中更新后,异步更新Redis缓存。可以使用消息队列(如RabbitMQ、Kafka等)来解耦数据库更新和缓存更新操作。例如,数据库更新商品信息后,发送一条消息到消息队列,由专门的消费者从消息队列中获取消息并更新Redis缓存。
    • 也可以设置缓存的过期时间(EXPIRE 命令),当缓存过期后,下一次请求时从数据库加载最新数据并重新缓存。
  2. 购物车
    • 对于购物车操作,在事务执行成功后立即更新缓存。例如,当用户添加或删除商品时,通过Redis事务确保购物车数据的一致性,同时在事务执行成功后,及时更新购物车对应的哈希结构。

故障恢复策略

  1. 持久化机制
    • 开启AOF(Append - Only File)持久化方式,在Redis配置文件中设置 appendonly yes。AOF会以日志的形式记录每次写操作,在Redis重启时通过重放AOF文件来恢复数据。同时,可以结合RDB(Redis Database)快照持久化,设置合适的快照保存条件(如 save 900 1 表示900秒内至少有1个写操作就进行快照),以便在故障后快速恢复数据。
  2. 主从复制与哨兵
    • 配置主从复制,将数据复制到多个从节点,提高数据的可用性。在从节点配置文件中设置 slaveof <masterip> <masterport>
    • 使用哨兵(Sentinel)机制来监控主节点的状态,当主节点发生故障时,自动进行主从切换。在哨兵配置文件(sentinel.conf)中设置监控的主节点信息等参数。

应对缓存雪崩、缓存穿透和缓存击穿问题

  1. 缓存雪崩
    • 设置不同过期时间:为不同商品设置随机的过期时间,避免大量缓存同时过期。例如,商品A的过期时间设置为1 - 2小时内的随机值,商品B的过期时间设置为2 - 3小时内的随机值。
    • 使用互斥锁:在缓存失效时,通过互斥锁(如 SETNX 命令)保证只有一个请求去加载数据库数据并更新缓存,其他请求等待。当第一个请求更新完缓存后,其他请求可以直接从缓存获取数据。
  2. 缓存穿透
    • 布隆过滤器:在查询数据前,先通过布隆过滤器判断数据是否存在。如果布隆过滤器判断数据不存在,则直接返回,不再查询数据库。布隆过滤器可以使用Redis的 BF.ADDBF.EXISTS 命令实现。
    • 缓存空值:当查询数据库发现数据不存在时,也将空值缓存起来,并设置较短的过期时间,避免每次都查询数据库。
  3. 缓存击穿
    • 热点数据不过期:对于热点商品,不设置过期时间,由后台定期更新缓存数据。
    • 互斥锁:与缓存雪崩中使用互斥锁类似,在单个热点数据缓存失效时,通过互斥锁保证只有一个请求去加载数据库数据并更新缓存。