缓存穿透:是指查询一个一定不存在的数据,由于缓存不会命中,需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都去数据库查询,造成缓存穿透。
解决方案:
1. 对所有可能查询的参数以hash形式存储,在控制层进行校验,若不符合查询条件则丢弃。或者采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
2.采用一个更为简单粗暴的方法,如果一个查询返回的数据为空,把这个空结果进行缓存,然后对这个数据设置过期时间,但它的过期时间会很短,最长不超过五分钟。
缓存雪崩:如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,则造成了缓存雪崩。
解决方案:
1.保证缓存层服务高可用性。即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务,比如 Redis Sentinel 和 Redis Cluster 都实现了高可用。
2.依赖隔离组件为后端限流并降级。在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
3.数据预热。可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
4.缓存并发。缓存并发是指,高并发场景下同时大量查询过期的key值、最后查询数据库将缓存结果回写到缓存、造成数据库压力过大。
5.分布式锁。在缓存更新或者过期的情况下,先获取锁,在进行更新或者从数据库中获取数据后,再释放锁,需要一定的时间等待,就可以从缓存中继续获取数据。