旁路缓存
- 关于其他缓存策略这里不做介绍
废话不多说直接上图
注意 写数据时候先写数据库,然后再删除缓存
那为什么不更新缓存而是删除呢?
- 思考1. 如果每次数据库发生写入操作,那么我们都更新缓存的话;假如某个场景数据库写入比较频繁,但是查询比较少,那我们是不是没有必要每次发生写入都更新缓存呢,直接删掉,当有读取请求的时候,去数据库拿一下数据,新增到缓存,是不是更合理呢?
- 思考2. 如果每次数据库发生写入操作,那么我们都更新缓存的话;假设缓存中的数据是通过连表查询出来的或者说sql比较复杂,那我们写入数据后每次都查一下db,更新缓存?是不是也没必要呢?
- 小结: 写db后删除缓存,当有读请求新增数据到缓存,本质是一个
Lazy
思想,就是啥时候用,我啥时候去读取db并设置到缓存,接下来的读取我都走缓存,当发生写数据库时候我再删除缓存,如此往复~~~。
缓存穿透
- 简单理解就是 , 客户(一般这种情况都是恶意攻击者) 在请求时候,故意绕过缓存中可能存在的key,搞一个一定不存在的key来
绕过
缓存,直接到db。(绕过
这个词有木有很形象???)
如何解决?
-
- 前后端都做校验,不符合情况的请求直接return
-
- 将 user:-1 缓存起来,当访问该key时候返回个默认值,but 假如他传的是user:-2,user:-3,user:-n呢?那么就用第三个方法
-
- 布隆过滤器,在数据库有修改时候,拿出数据拼接为key,同步至布隆过滤器。每次请求过来时候,都校验一下,如果布隆过滤器中有,那说明在数据库中
(可能有,也就是说不一定有(不过这个概率一般比较小) ),如果布隆过滤器告诉你没有,那说明肯定没有
。直接return
- 布隆过滤器,在数据库有修改时候,拿出数据拼接为key,同步至布隆过滤器。每次请求过来时候,都校验一下,如果布隆过滤器中有,那说明在数据库中
-
- 或许在某些情况下我们的数据量不大,也不想忍受布隆过滤器的误判,那么我们可以使用hash结构来存储key,每次请求来时,去hash中找下,这样肯定不会有误判的几率啦。
-
- 或者我们可以使用 bitMap 和hash类似,看情况进行选择啦,另外需要知道bitmap的缺点。这个bitmap我会在后续文章中写到。
缓存击穿
- 简单理解就是 , 客户(也有可能是恶意攻击者) 在请求时候,故意只查询缓存中的某个(或者说某几个)key,这些key在缓存中存在还好,一旦不存在,那请求都会到你的db,就像是对着A身上某个点一直射击,等A身上防弹衣失效时候,A也就gg了。
(可能这个例子不太合理,咱们姑且认为防弹衣也是有过期时间的吧 哈哈)
如何解决?
-
- 其实根据击穿的原因我们就能想到,10万个请求都查询某条数据,(或者说某几个数据,为了方便我们就假设10万个请求参数都是同一个哈),那我是不是得加个分布式锁啊,既然你们请求的数据都一样,那我只让一个请求落到db,你们先等一会,他查完后立马更新缓存,你们(99999)个请求都去查询缓存就好了。
-
- 二级缓存,但是这样的话,需要多维护一层缓存,也加大了复杂度,我觉得该方法是比较少用的总之目前为止我还没用过此方式。
-
- 设置热点key不过期,至于什么是热点key那就得根据业务来啦。
缓存雪崩
- 顾名思义就是redis中的key同一时间失效(就像雪山崩塌一样)
一般都是设置的过期时间一样,或者说定时任务定时清理某批key
, 那么客户在此刻请求,也会直接到我们的db。
如何解决?
-
- 不定时批量删除key
-
- 热点key一直存留在redis中,当发生更新的时候(需要我们在业务上去判断)去更新热点key就好了,
-
- 那么如果一些key属于非热点key呢?那么好办我们在设置过期时间的时候 设置个随机值就好啦。避免同一时间失效引发雪崩问题
好了本文到这里就结束了,下一篇准备bitMap了