添加缓存
模型分析
原来的模型,客户端的请求直接被转到数据库进行查询
增加中间层(redis)
缓存穿透
缓存穿透是指 客户端请求的数据缓存和数据库中都不存在,这样缓存永远不会生效,请求一直被打进数据库中。
例如:用户请求数据,例如ID为负数。
解决方法:
1、无意义数据放入缓存,下一次相同请求就会命中缓存;
2、IP过滤;
3、参数校验;
4、布隆过滤器;
缓存空对象
把空的值缓存到redis中
缺点:
额外的内存消耗(可以设置比较短的过期时间)
可能造成短期的不一致(如果设置空到缓存之后刚好又插入了对应数据)
布隆过滤
布隆过滤器怎么知道数据存不存在呢?
布隆过滤器会将键(不含值)以一定的哈希算法映射到一个二进制数组中,如果布隆过滤器中未表示有此值,则一定没有。标识有则大概率有。(因为一个值计算出hash之后如果对应位数组为0则一定是没有,对应位数组为1可能是因为其他数据hash映射也正好是这里)
因为布隆过滤是bitmap二进制数组,占用量很小
主动防御
上面两种都是被动的方式,当然也可以主动去防止缓存穿透
基础格式校验
如果使用ID查询,可以使用非常复杂的ID规则,别人就不好猜测ID的规律去发送请求。如果是乱写的请求,可以通过检验是否符合ID的规则直接进行过滤。
用户权限校验
接口有权限,哪些用户可以访问,对于用户访问频率限流
缓存雪崩
缓存雪崩是指在同一时间内大量缓存key同时失效或者redis服务器宕机,导致大量请求到达数据库,带来巨大压力。
解决方法
解决方案
- 给不同的Key的TTL添加随机值(避免同一时间失效)
- 利用Redis集群提高服务的可用性(让缓存节点分布在不同的物理节点上)
- 生成不失效的缓存数据
- 定时任务更新缓存数据
- 给缓存业务添加降级限流策略
-
- 如果redis宕机了,mysql必须顶住,我们可以主动拒绝一些服务,把服务量压缩到数据库可承受的范围内
- 给业务添加多级缓存
-
- 代理nginx可以加缓存,后端(比如go)也可以加缓存,然后redis和mysql
缓存击穿
缓存击穿是热点key的问题,高并发访问并且缓存重建业务较复杂的key突然失效了,无数请求到达数据库端,给数据库造成巨大冲击。(少量key,大量访问)
缓存重建复杂:实际业务中,不是单纯查询出来缓存那么简单,可能缓存的结果来自于一个多表查询和计算出来的产物。
在这个漫长的重建缓存的过程中,会有无数请求不断打入数据库
解决方案
互斥锁
利用锁机制,只让一个进行重建。只有获取锁成功的线程才能进行写入缓存
简而言之,就是在缓存重建时让访问进程由并发执行变成串行执行
这个方案有个最大的问题,互相等待。(在创建的时候涌入的所有进程都只能在那等待)
逻辑过期
相当于redis中expire为0,永不过期(一般来说这个问题出现在活动业务比较多,如果活动持续一个月,那么过期时间直接设置成一个月或者直接不过期,等待活动结束一并删除)。但是数据中会有个字段控制过期时间,每次拿数据进行一下逻辑判断,如果过期了,就去数据库更新数据。更新数据的过程也用到了锁机制,但是如果获取不到锁,则会直接返回旧的数据而不是等待。
这个方案最大的问题是不能保证一致性,它会返回过期的数据