51mee - AI智能招聘平台Logo
模拟面试题目大全招聘中心会员专区

在游戏排行榜系统中,使用Redis缓存用户排名数据,如何避免缓存雪崩、缓存击穿和缓存穿透问题?请给出解决方案。

9377游戏后端开发难度:中等

答案

1) 【一句话结论】在游戏排行榜系统中,通过动态调整缓存过期时间(结合数据更新频率)、对热点key加分布式锁/预加载、使用布隆过滤器/空值缓存,并辅以多级缓存(如Redis+Memcached)和预加载策略,可有效避免Redis缓存雪崩、击穿、穿透风险,保障系统稳定与性能。

2) 【原理/概念讲解】

  • 缓存雪崩:指大量缓存数据同时过期失效,导致所有请求直接访问后端数据库,引发DB压力激增。类比:所有用户同时抢热门商品,服务器瞬间崩溃。
    解决方案:为缓存设置随机过期时间(原过期时间±动态偏移量,偏移量根据数据更新频率调整:更新频率低则偏移量取±300秒,更新频率高则取±30秒);对热点数据预加载,分散过期时间;结合多级缓存(如Redis+Memcached)分担压力。
  • 缓存击穿:指某个热点key(如排行榜TOP1用户)突然失效,所有后续请求都直接访问DB,导致DB瞬间压力过大。类比:热门景点突然关闭,所有游客涌向入口拥堵。
    解决方案:对热点key加分布式锁(如Redis的SETNX),锁获取成功时才查询DB并缓存;提前预加载热点key(如排行榜TOPN用户),避免失效。
  • 缓存穿透:指查询不存在的key(如用户ID为0或不存在的用户排名),导致所有请求都直接访问DB,且DB中无数据,导致无效查询。类比:在图书馆找不存在的书,所有读者都问管理员,浪费资源。
    解决方案:使用布隆过滤器(Bloom Filter)提前过滤不存在的key;或对不存在的key缓存空值(如缓存1小时,避免后续重复查询)。

3) 【对比与适用场景】

问题类型定义核心原因解决方案适用场景注意点
缓存雪崩大量缓存同时失效,导致DB压力激增缓存统一过期时间,或系统故障导致大量缓存失效随机过期时间、过期时间偏移、多级缓存热点数据集中过期(如定时任务清空缓存)偏移量需动态调整,避免极端情况集中失效
缓存击穿热点key失效,所有请求直接访问DB热点key突然失效,无缓存互斥锁、预加载、热点key预热排行榜TOP1用户、活动奖品等高频访问key锁粒度尽量小,避免影响其他用户;锁过期时间设10-30秒,防止死锁
缓存穿透查询不存在的key,导致无效DB查询查询不存在的key,无缓存布隆过滤器、空值缓存查询不存在的用户ID、恶意攻击请求布隆过滤器需根据用户ID范围调整位数,降低误判率;空值缓存需设置合理过期时间

4) 【示例】

  • 缓存雪崩(动态随机过期):
    # 动态计算偏移量(根据更新频率)
    def get_random_offset(update_frequency):
        if update_frequency < 60:  # 每分钟更新
            return random.randint(-30, 30)
        elif update_frequency < 1440:  # 每小时更新
            return random.randint(-300, 300)
        else:  # 每天更新
            return random.randint(-3000, 3000)
    
    expire_time = 3600 + get_random_offset(60)  # 1小时±30秒(更新频率高)
    redis.setex("user_ranking:1001", expire_time, json.dumps(ranking_data))
    
  • 缓存击穿(分布式锁):
    import redis
    import time
    
    r = redis.Redis()
    lock_key = f"lock:user_ranking_top1"
    lock_value = str(time.time())
    
    # 尝试获取锁
    if r.set(lock_key, lock_value, ex=15, nx=True):
        ranking = r.get("user_ranking:1001")
        if not ranking:
            ranking = query_db("SELECT * FROM user_ranking WHERE user_id=1001")
            r.setex("user_ranking:1001", 3600, json.dumps(ranking))
        r.delete(lock_key)
    else:
        # 锁获取失败,重试
        time.sleep(1)
        retry()
    
  • 缓存穿透(布隆过滤器):
    from pybloom import BloomFilter
    
    bloom_filter = BloomFilter(capacity=1000000, error_rate=0.001)  # 假设用户ID范围0-100万
    
    # 查询前检查布隆过滤器
    if not bloom_filter.contains(user_id):
        return "用户不存在"
    
    ranking = query_db("SELECT * FROM user_ranking WHERE user_id=?", user_id)
    r.setex(f"user_ranking:{user_id}", 3600, json.dumps(ranking))
    

5) 【面试口播版答案】
“面试官您好,针对游戏排行榜的Redis缓存问题,我总结三个方案:首先缓存雪崩,是大量缓存同时过期导致DB压力,解决方法是给缓存设置随机过期时间,比如原过期时间±300秒(更新频率低时),或者对热点数据预加载,分散失效时间;其次缓存击穿,是热点key失效后所有请求去DB,解决方法是给热点key加分布式锁(比如用SETNX),锁成功才查DB并缓存,或者提前预加载;最后缓存穿透,是查询不存在的key导致无效查询,解决方法是布隆过滤器过滤,或者缓存空值。比如排行榜TOP1用户用锁保证同一时间只有一个线程查DB,不存在的用户ID用布隆过滤器判断,避免无效查询。这样就能避免风险。”

6) 【追问清单】

  • 问题1:缓存雪崩的随机过期时间偏移量怎么确定?
    回答要点:根据数据更新频率,更新频率低则偏移量大(如±300秒),更新频率高则小(如±30秒)。
  • 问题2:缓存击穿用锁的粒度问题?
    回答要点:锁粒度尽量小(仅热点key),避免影响其他用户;锁过期时间设10-30秒,防止死锁。
  • 问题3:极端情况(如系统故障)怎么办?
    回答要点:多级缓存(Redis+Memcached)分担压力,预加载失败有回退策略。

7) 【常见坑/雷区】

  • 固定过期时间导致雪崩:错误,正确做法是随机过期或偏移。
  • 全局锁影响性能:错误,锁粒度应小,避免影响其他用户。
  • 布隆过滤器误判率忽略:错误,需根据场景调整参数。
  • 不缓存空值导致重复无效查询:错误,应缓存空值。
  • 锁过期时间过短导致死锁:错误,需设置合理过期时间(如10-30秒)。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1