高并发缓存实践之-缓存穿透、缓存雪崩、缓存并发

前言

缓存在我们的应用程序会被大量使用,它给程序性能带来质的提升的同时,也可能会因为使用不当而造成不可挽回的损失

本章节我们就来重点梳理一下由于高并发量而导致的缓存问题出现的原因和解决方案

缓存穿透

缓存穿透是指查询缓存和数据库中都不存在的数据,特别是在高并发场景下,缓存无法命中,导致每次请求都要穿透到数据库上,造成数据库短时间内承受大量请求而宕机

解决方案

  • 缓存空值,设定失效时间:以不影响具体为务为准,比如30秒,可以防止攻击者使用同一参数进行大量的暴力攻击

  • 校验过滤请求参数:攻击者往往会猜到第一个方案,所以每次攻击都会使用不同的参数,比如orderId< 0的情况,校验程序需要对参数格式进行过滤,不符合规则的请求直接拒绝

  • 布隆过滤器:将数据库中的数据通过某种算法hash到一个足够大的bitmap中,通过查询bitmap判断哪些数据一定是不存在的,从而拦截掉该次请求【:常用的布隆过滤器实现:Redis BitMap

缓存雪崩

缓存雪崩是指缓存服务器重启或者大量缓存在某一个时间段内失效,造成数据库瞬时负载压力升高,甚至压垮数据库

解决方案

  • 缓存数据设置不同的失效时间:不同的数据使用不同的失效时间,甚至对相同的数据、不同的请求使用不同的失效时间 [推荐]

  • 缓存预热:针对服务器重启的场景,提前将热点数据进行缓存

  • 本地锁:建议使用 双重检查锁 的方式,当某一个键在缓存中不存在,在查询数据库前给当前线程加一个锁,数据库操作完成后更新缓存,最后释放锁,其它线程就会从缓存中获取数据并返回

缓存并发

缓存并发有时也被称作缓存击穿,即:数据库和缓存都存在数据,当该数据在缓存中某一时刻失效时,大量的请求同时判断到该数据已过期,因此会同时访问数据库来查询最新数据并写回缓存,造成数据库压力瞬间提高

解决方案

  • 分布式锁:保证每个key同时只有一个线程去查询数据库,这种方式将高并发的压力转移到了分布式锁,所以需要评估分析分布式锁的性能

  • 本地锁:该方式在缓存雪崩中也有使用,但是这种方法只能作用于一个服务实例,对于多实例服务的场景,还是会有多个数据库查询操作。毕竟,相对于高并发请求和实例数来讲,该方式还是非常有效的解决了缓存并发的问题 [推荐]

  • 设置热点数据永不过期:缓存不过期就不会出现缓存并发击穿的情况,由业务程序判断是否过期并更新延长过期时间。例如:启动一个定时任务,判断数据是否更新(如版本号),如果更新则修改缓存并延长过期时间,如果未更新则只延长过期时间

你可能感兴趣的:(分布式)