面试问题汇总缓存击穿、缓存失效、热点Key解决方案

本文探讨了缓存击穿、缓存雪崩及热点Key等问题,提供了多种解决方案,如二级缓存、布隆过滤器、主从配置等,有效提升系统性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

缓存击穿、缓存失效、热点Key解决方案

缓存击穿: 查询一个数据库中不存在的数据,比如商品详情,查询一个不存在的ID,每次都会访问DB,如果有人恶意破坏,很可能直接对DB造成过大的压力。

解决方案

1.增加二级缓存。查询时,如果key不存在,且DB中无数据,对这个不存的key设置一个标识key,进行缓存。以后再查询key时,先查询标识缓存,如果标识缓存存在则返回一个false或者NULL值的默认值,APP做相应处理。这个标识key的失效时间不能太长。一般5分钟左右。

2.查询时,key不存在且DB中无数据,直接将KEY和NULL缓存进去,并且返回App,当然这个缓存过期时间会很短。

3.采用布隆过滤器,将所有的DB数据缓哈希到一个足够大的bitMap中,一个一定不存在的数据会被这个bitMap拦截掉,从而避免了对底层存储系统的查询压力。

缓存雪崩:可能是因为数据未加载到缓存中,或者同一时间缓存大面积的失效,从而导致所有的请求都去查询数据库,导致数据库CPU和内存负载过高,甚至宕机。

解决方案:

1.加锁计数(即限制并发数量)或者起一定数量的队列来避免缓存失效时大量的请求并发到数据库。但这种方式会降低吞吐量。

2.分析用户行为,然后均匀分布缓存失效时间。或者在失效时间的基础上再加上1~5分钟的随机数。

3.如果是某台缓存服务器宕机,可以考虑做主从配置。

热点KEY:缓存中的某些key对应的value存储在集群中的一台机器上,使得所有的流量涌向同一台机器,称为系统瓶颈,该问题的挑战在于不能用增加机器容量来解决。

解决方案:

1.客户端热点key缓存:将热点key对应的value缓存到客户端本地,并且设置一个失效时间。对于每次请求,先检查key是否存在于本地缓存中,如果有则直接返回,不去访问分布式缓存的机器。当然失效时间不能太长。

2.将热点key分散为多个子KEY,然后存储到缓存集群不同的机器上,这些子key的value和key的value是一样的。当通过热点key去查询数据是,通过某种hash算法随机去选择一个子key,然后去访问缓存机器,将压力分散到不同的机器上。

3.“永不过期”:

    这里的"永不过期"包含两层意思:

     (1)从redis看,不设置过期时间,这就保证了不会出现热点key过期问题,也就是“物理”的不过期。

     (2)从功能上看,把过期时间设置在key对应的value里,如果发现要过期了,通过一个后台异步线程进行缓存的构建,这个过期时间,也就是“逻辑”上的不过期。从实战看,这种方法对于性能非常的友好,唯一不足的就是构建缓存的时候,其余线程可能访问的是老数据,但是对于一般互联网功能来说这个也是可以接受的。

    String get(final String key) {  
            V v = redis.get(key);  
            String value = v.getValue();  
            long timeout = v.getTimeout();  
            if (v.timeout <= System.currentTimeMillis()) {  
                // 异步更新后台异常执行  
                threadPool.execute(new Runnable() {  
                    public void run() {  
                        String keyMutex = "mutex:" + key;  
                        if (redis.setnx(keyMutex, "1")) {  
                            // 3 min timeout to avoid mutex holder crash  
                            redis.expire(keyMutex, 3 * 60);  
                            String dbValue = db.get(key);  
                            redis.set(key, dbValue);  
                            redis.delete(keyMutex);  
                        }  
                    }  
                });  
            }  
            return value;  
        }  

 

### Redis 面试汇总 2025年最新版 #### 缓存雪崩、缓存穿透、缓存击穿 缓存雪崩指的是当大量的缓存数据在同一时间失效时,所有的请求都会直接访问数据库,可能导致数据库崩溃。解决方法包括为缓存设置随机的过期时间以及提前加载热点数据到缓存中[^2]。 缓存穿透描述的是某些恶意或者错误的请求反复查询数据库和Redis中都不存在的数据的情况。这会使得这些无效请求频繁地到达数据库层面,增加其负担甚至导致崩溃。解决方案可以通过接口层校验来阻止非法请求(如ID小于零),并利用布隆过滤器减少不必要的数据库查询次数。 缓存击穿则是指某个特定的热门键突然失效,所有对该键的请求瞬间转向后台数据库造成压力过大而失败的现象。对此的有效措施是对非常重要的热数据设定永不超时属性或是返回一个默认值为空字符串给客户端以减轻服务器负载。 #### 数据库与Redis的一致性保障机制 为了确保数据库同Redis之间维持一致状态,通常采取如下几种方式:双写模式即每次更新操作同时作用于两者之上;基于消息队列实现异步同步流程,在主存储完成修改后再通过事件通知副本进行相应调整;定期全量对比修复差异项从而达到最终一致性目标等等。 #### Redis 的内存淘汰策略 当Redis作为缓存使用时遇到可用内存不足以容纳新增加项目的情形下,则需依据预先定义好的规则决定哪些现有条目应该被清除出去以便腾出空间接纳新的对象进来。常见的算法有LRU(Least Recently Used), LFU (Least Frequently Used)等不同类型的驱逐政策可供选择应用取决于具体业务需求场景下的优先级考量因素[^1]。 ```python import redis # 创建连接池 pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True) r = redis.Redis(connection_pool=pool) # 设置 key-value 并指定存活时间为随机数秒模拟防止集体到期现象发生 for i in range(100): r.set(f'key{i}', f'value{i}', ex=int(random.uniform(86400, 172800))) ``` 上述代码片段展示了如何向Redis实例批量插入带有随机生存期限的数据记录,以此作为一种预防手段对抗可能出现的大面积集中式过期风险问题——也就是所谓的“缓存雪崩”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值