面试题答案
一键面试可能出现的问题及解决方案
缓存穿透
- 问题描述:查询一个不存在的数据,由于缓存中没有,每次都会去数据库查询,若大量这样的请求,会给数据库带来巨大压力,甚至压垮数据库。
- 解决方案:
- 布隆过滤器:在查询数据库前,使用布隆过滤器判断数据是否存在。布隆过滤器可以快速判断一个元素一定不存在或者可能存在。如果布隆过滤器判断不存在,则直接返回,不会查询数据库;如果判断可能存在,再去查询数据库并将结果存入缓存。
- 空值缓存:当查询数据库发现数据不存在时,也将空值缓存起来,并设置较短的过期时间,这样后续相同查询直接从缓存返回空值,减少对数据库的查询压力。
缓存雪崩
- 问题描述:大量缓存数据在同一时间过期,导致大量请求同时访问数据库,使数据库压力骤增,甚至可能导致数据库崩溃。
- 解决方案:
- 随机过期时间:给缓存设置过期时间时,采用随机值,避免大量缓存集中过期。例如原本设置过期时间为1小时,可以在50分钟到70分钟之间随机设置过期时间。
- 二级缓存:使用两层缓存,一级缓存设置较短过期时间,二级缓存设置较长过期时间。当一级缓存过期时,先从二级缓存获取数据,同时异步更新一级缓存,减少对数据库的访问频率。
- 缓存预热:在系统上线前,提前将热点数据加载到缓存中,并设置合理的过期时间,避免上线后大量缓存同时过期。
缓存击穿
- 问题描述:热点数据的缓存过期瞬间,大量请求同时访问,这些请求都会去查询数据库,给数据库带来巨大压力。
- 解决方案:
- 互斥锁:在缓存过期时,只允许一个线程去查询数据库并更新缓存,其他线程等待。查询到数据并更新缓存后,其他线程再从缓存获取数据。可以使用分布式锁(如Redis的SETNX命令实现简单的分布式锁)来保证同一时间只有一个线程能查询数据库。
- 永不过期:对于热点数据设置永不过期,同时采用异步线程定时更新缓存数据,这样可以避免缓存过期瞬间的高并发问题。但要注意异步更新缓存时数据一致性的问题,需确保更新过程中的数据正确性。
数据一致性保证
- 双写一致性问题:在数据更新时,先更新数据库再更新缓存,或者先更新缓存再更新数据库,都可能因为中间步骤出现异常导致数据不一致。
- 解决方案:
- 先更新数据库,再删除缓存:这是相对常用的策略。更新数据库成功后,删除缓存,下次查询时会重新从数据库加载数据到缓存。但如果删除缓存失败,可能会导致数据不一致。可以通过重试机制,多次尝试删除缓存;或者记录删除失败的缓存键,通过异步任务进行补偿处理。
- 使用消息队列:将数据更新操作发送到消息队列,确保数据库和缓存的更新顺序一致且可靠。消息队列按顺序处理更新消息,先更新数据库,再更新缓存或删除缓存,避免并发更新导致的数据不一致问题。