自己的话:查缓存和数据库都没有的数据
产生原因:访问的数据即不在缓存,也不在数据库。
解决方案:
概述
缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久化层数据库查询,发现也没有,于是本次查询失败,当用户很多的时候,缓存都没有命中(秒杀!),于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
要解决这类问题最首先的思路是在接入层做好数据的校验,比如 id 是否正整数、key 是什么类型、参数的范围等。在入口层就把所有规则上不合法的请求拦在 Redis 之外,自然就没有穿透的现象发生了。
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;
但是这种方法会存在两个问题:
1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键; 2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
缓存空值这方案看似很完美,但实际上只能防止正常用户的穿透行为。如果是真正的攻击者,他并不会一直用同一个值去请求,例如 id 最大值是 999999,攻击者可能会从 9999991 开始,9999992、9999993……逐个试,这样既能通过我们的合法检查,又能穿透我们的缓存。如果只用缓存空值的方案,很可能整个缓存会一直被这种“空数据”污染。
不断缓存空值可能会造成空数据污染
所以如果采取空数据缓存,一定要在上游就针对恶意的攻击做好对应的频控(例如 ip 维度),侦测到类似的恶意请求,则直接拒绝,或者直接返回一些假数据/降级数据等,以保护缓存不被穿透。