缓存穿透
描述:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,且请求的数据均为不存在的数据(id为-1这种)。
解决方案:
- 接口进行参数校验,将必要的参数进行基础校验,超过参数范围则直接拦截;
- 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。
缓存击穿
描述:缓存击穿是指缓存中没有但数据库中有的数据,由于并发用户特别多,同时读缓存没读到数据,造成大量的请求读取Mysql数据库,造成Mysql负担过重。
解决方案:
-
缓存空对象,如果缓存层和存储层都不命中后,仍然将空对象保留到缓存中,这样就保护了后端数据源。
-
问题:空值做了缓存, 意味着缓存层中存了更多的键, 需要更多的内存空间(如果是攻击, 问题更严重) , 比较有效的方法是针对这类数据设置一个较短的过期时间, 让其自动剔除。 第二, 缓存层和存储层的数据会有一段时间窗口的不一致, 可能会对业务有一定影响。例如过期时间设置为5分钟, 如果此时存储层添加了这个数据, 那此段时间就会出现缓存层和存储层数据的不一致, 此时可以利用消息系统或者其他方式清除掉缓存层中的空对象
-
-
bloom过滤器拦截:在访问缓存层和存储层之前, 将存在的key用布隆过滤器提前保存起来, 做第一层拦截。 例如: 一个推荐系统有4亿个用户id, 每个小时算法工程师会根据每个用户之前历史行为计算出推荐数据放到存储层中, 但是最新的用户由于没有历史行为, 就会发生缓存穿透的行为, 为此可以将所有推荐数据的用户做成布隆过滤器。 如果布隆过滤器认为该用户id不存在, 那么就不会访问存储层, 在一定程度保护了存储层。这种方法适用于数据命中不高、 数据相对固定、 实时性低(通常是数据集较大) 的应用场景, 代码维护较为复杂, 但是缓存空间占用少。可以参考下图:
解决缓存击穿 | 使用场景 | 维护成本 |
缓存空对象 |
|
|
布隆过滤器 |
|
|