缓存穿透:
定义:缓存穿透指的是请求查询缓存和数据库中都不存在的数据,从而导致每次请求都直接访问数据库。
原因:通常是由于恶意请求、非法输入或系统漏洞导致的。攻击者故意提交无效的查询,绕过缓存直接访问数据库。
影响:频繁的缓存穿透会导致数据库负载增加,消耗额外的资源,并可能引起拒绝服务(Denial of Service)攻击。
缓存击穿:
定义:缓存击穿指的是一个热点数据失效或被删除后,大量并发请求同时到达系统并请求该数据,导致缓存无法命中而直接访问数据库。
原因:通常是由于热点数据过期、手动删除、大量并发请求或非法请求引起的。
影响:缓存击穿会导致数据库负载剧增,大量请求直接访问数据库,降低了系统性能,甚至可能导致数据库崩溃。
缓存雪崩:
定义:缓存雪崩指的是缓存中大量数据同时失效或缓存系统不可用,导致大量请求直接访问数据库,对数据库造成巨大压力。
原因:通常是由于缓存过期时间集中、缓存依赖关系或缓存系统故障引起的。
影响:缓存雪崩会导致系统性能下降、响应延迟增加甚至系统崩溃,严重影响系统的可用性。
综上所述,缓存穿透是指访问缓存和数据库都不存在的数据,缓存击穿是指热点数据失效导致请求直接访问数据库,而缓存雪崩是指大量缓存数据同时失效或缓存系统不可用,导致大量请求直接访问数据库。这些问题都会对系统性能、可用性和安全性造成负面影响。
缓存击穿:缓存击穿是指在使用缓存的场景下,当某个热点数据失效或不存在时,大量并发请求同时访问该数据,导致请求都穿透缓存直接访问后端数据库,造成数据库负载过大。解决方案通常包括加锁、互斥锁、预加载等方法。
热点数据失效:当某个热点数据的缓存失效,并且有大量请求同时访问该数据时,会导致缓存击穿。
冷启动问题:当系统刚启动或者缓存被清空时,大量请求同时访问未缓存的数据,也会引发缓存击穿。
加锁机制:在请求缓存失效时,只允许一个请求去查询数据库,其他请求等待。当第一个请求完成数据库查询后,将结果回写到缓存中,其他请求再从缓存获取数据。这样可以避免大量请求同时访问数据库。
互斥锁(Mutex):在缓存失效时,利用互斥锁机制阻止并发请求查询数据库。通过在代码层面加锁,保证只有一个线程执行查询操作,其他线程等待并直接从缓存获取数据。
预加载(Cache Pre-warming):在系统启动或空闲期间,预先将热点数据加载到缓存中。这样可以避免冷启动时大量请求直接访问数据库。
设置短暂的缓存过期时间:当缓存失效后,设定较短的过期时间,避免大量请求在同一时间窗口内访问数据库。
响应穿透检测:在缓存层对请求进行合法性检测,如果请求的数据在数据库中不存在,可以将该键对应的缓存值设置为空值或者特殊标记,避免反复查询数据库。
缓存穿透:缓存穿透是指查询一个不存在于缓存和数据库中的数据,导致每次请求都必须查询数据库,而且该数据永远不存在于缓存中,从而浪费了大量的数据库资源。缓存穿透可能因为恶意攻击、非法请求或者系统错误等原因引起。解决方案通常包括设置空值缓存、布隆过滤器、热点数据预加载等方法。
恶意请求:攻击者故意发送无效的查询或非法输入,以绕过缓存直接访问数据库。
数据库中不存在的数据:频繁查询缓存和数据库中都不存在的数据。
布隆过滤器(Bloom Filter):使用布隆过滤器来过滤掉那些明显不存在于数据库中的请求。布隆过滤器是一种高效的数据结构,它可以快速判断某个元素是否存在于集合中。
缓存空对象(Cache null objects):当查询数据库后发现数据不存在时,将结果也缓存下来,但设置一个较短的过期时间。这样,在下一次请求相同数据时就可以从缓存中获取结果,而不需要再次访问数据库。
异常请求拦截(Request filtering):对于异常请求或频繁请求的IP地址,可以采取一定的限流或封禁策略,以减轻对数据库的负载。
缓存预热(Cache warming):在系统启动或低峰期,提前将一些热门数据加载到缓存中,避免冷启动时大量请求直接访问数据库。
数据合法性校验:在接收到请求后,进行合法性校验,例如检查参数的有效性、鉴权等,避免非法请求绕过缓存直接访问数据库。
异步加载数据:对于不存在于缓存中的数据,可以通过异步方式加载数据,并将其缓存起来。这样,在下一次请求相同数据时就可以从缓存中获取结果,而不需要再次访问数据库。
缓存雪崩是指在缓存中的大量数据同时失效或者缓存系统不可用导致大量请求直接访问数据库,从而对数据库造成巨大压力。这种情况下,数据库可能会无法承受如此大的并发请求负载,导致系统性能下降甚至崩溃。
缓存过期时间集中:当大量缓存的过期时间设置在相近的时刻,或者由于缓存系统异常导致所有缓存同时失效,会导致大量请求在同一时间窗口内穿透缓存去查询数据库。
缓存依赖关系:如果缓存之间存在依赖关系,并且其中一个缓存失效后,其他缓存也无法得到有效更新,会导致相关依赖的数据请求直接访问数据库。
缓存系统故障:当缓存系统发生故障且无法提供服务时,所有的请求都无法命中缓存,只能直接请求数据库,使得数据库承受巨大的负载压力。
使用多级缓存和热点数据预加载,减少缓存失效的风险。
合理设置缓存过期时间,避免过多缓存同时失效。
设置随机的缓存过期时间,避免大量缓存在同一时间失效。
实施缓存的容灾备份,确保即使一个缓存节点故障,整个系统仍能正常运行。
在关键路径上增加限流措施,避免过多请求同时访问数据库。
举个例子,就类似于百度这种搜索场景。 如果每天大量的人搜索数据,然后去mysql等这种数据库的磁盘中,查询数据。在磁盘中读取数据,比较慢,会对数据库造成很大压力。
所以 将一些很多人访问的数据(称为热点数据),缓存到redis中。 用户进行搜索的时候,是先去redis 查询数据,如果有数据,则直接返回,如果在redis中查不到数据,然后再去查mysql这种数据库。(这样是比较消耗性能的)
热点数据就是某一段时间内,用户大量访问数据。比如设置某条数据如果十分钟被访问超过5次,则称为热点数据,存在redis中。某条热点数据,在十分钟内被访问没有超过5次,则会被释放掉。
redis缓存穿透:
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求。由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。
先查redis缓存,查不到,再去查存储层 这样是非常消耗性能的。
在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
缓存击穿:
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
利用缓存击穿攻击:
还是举搜索的例子,redis存的是热点数据。普通用户进行搜索时,先读取redis缓存,如果读不到,才去mysql数据中读。
当别人攻击时,它会利用大量的生僻词去进行搜索,这些数据在redis里没有,会去读取mysql磁盘,消耗大量的性能。 并且使用 这些生僻的词变成热点数据,存贮在redis缓存中。
此时,正常用户,再去访问时,在redis缓存中,存贮的都是生僻的词,查不到他们的数据,则会再次去mysql中查询数据。造成性能的消耗。