缓存的设计一般都遵循以下流程:
1、业务系统发起一个查询请求,首先会在缓存中判断是否存在对应结果的数据
2、如果缓存中存在,则直接返回数据结果
3、如果缓存中不存在,则会去数据库中查询对应数据,并更新缓存,然后返回数据结果
我们在面试时,问道的关于缓存的问题很多,但是涉及实际场景的题目一般可以分为以下三类:
1、缓存穿透:
当业务系统需要查询的数据根本在数据库中不存在时,每一次的查询请求都会最终对数据库造成一次查询,这种情况称为缓存穿透,即业务访问根本不存在的数据。
危害:这种情况下,如果有大量的请求查询根本不存在的数据,那么这些请求将直接对数据库造成冲击,会使得数据库压力很大。大多数情况下为恶意攻击,故意营造大量不存在的数据请求我们的服务,由于缓存中并不存在这些数据,因此海量请求均落在数据库中,从而可能会导致数据库崩溃。
解决方案:1、缓存空数据:即将空数据null也做成一个缓存结果,这样在下次有相同请求到来时,缓存可以拦截该请求,返回缓存中的结果。2、使用BloomFilter,它需要在缓存之前再加一道屏障,里面存储目前数据库中存在的所有key。当业务系统有查询请求的时候,首先去BloomFilter中查询该key是否存在。若不存在,则说明数据库中也不存在该数据,因此缓存都不要查了,直接返回null。若存在,则继续执行后续的流程,先前往缓存中查询,缓存中没有的话再前往数据库中的查询。
2、缓存雪崩:
如果缓存在某个时刻挂了,那么大量的请求也将会直接访问数据库,造成很大压力。
危害:如果缓存因某种原因发生了宕机,那么原本被缓存抵挡的海量查询请求就会像疯狗一样涌向数据库。此时数据库如果抵挡不了这巨大的压力,它就会崩溃。
解决方案:1、使用缓存集群,增大可用性,当一个缓存挂了还有其他的缓存跟上。2、使用Hystrix,它是一款开源的“防雪崩工具”,它通过 熔断、降级、限流三个手段来降低雪崩发生后的损失。
3、热点数据集中失效:
如果某一个热点数据失效,那么当再次有该数据的查询请求时就会前往数据库查询。但是,从请求发往数据库,到该数据更新到缓存中的这段时间中,由于缓存中仍然没有该数据,因此这段时间内到达的查询请求都会落到数据库上,这将会对数据库造成巨大的压力。此外,当这些请求查询完成后,都会重复更新缓存。
危害:对于一些请求量极高的热点数据而言,一旦过了有效时间,此刻将会有大量请求落在数据库上,从而可能会导致数据库崩溃。
解决方案:1、使用互斥锁,上锁的对象为key,当失效后的第一个查询请求到来时,就会对缓存上锁,这时其他的查询请求就会被挡在外面,只有一个查询请求去访问数据库,知道缓存中更新了这个结果之后,剩余的查询请求才可查询缓存。2、对于很多热点数据集中失效,可以设置不同的失效时间,这样可以错开一部分热点数据的更新时间