今天520,要及时「缓存」你们的珍贵时光。(二)

简介: 在很久很久以前人类和洪水作斗争的过程中,水库发挥了至关重要的作用 : 在发洪水时可以蓄水,缓解洪水对下游的冲击;在干旱时可以把库存的水释放出来以供人们使用。这里的水库就起着缓存的作用。在如今互联网的世界里随着互联网的普及,内容信息越来越复杂,用户数和访问量越来越大,我们的应用需要支撑更多的并发量,同时我们的应用服务器和数据库服务器所做的计算也越来越多。

解决方案一

  • 首先我们能想到的就是在网关参数进行过滤。校验请求的 key 是否是我们系统 key 的格式等

当然这网关层所能做到的只是一些简单过滤。每个后端的设计人员应该对服务的可用性和健壮性负责。接下来我们看看服务端应该如何处理

  • 服务端可以将不存在的 key 暂时保存到我们的缓存中,再次接收到同样的请求后如果直接命中缓存并且值为空那么就会直接返回,不会穿透到数据库层面,这样就避免了缓存击穿。

但是黑客/恶意攻击者是不会这么轻易被打发的。每次请求都会传不同的 key 来攻击我们的服务。这个时候这个方案起不到作用了。

解决方案二

构建一个 BloomFilter(布隆过滤器) 缓存过滤器,记录全量数据。这样访问数据时,可以直接通过 BloomFilter 判断这个 key 是否存在,如果不存在直接返回即可,根本无需查缓存和 DB。这样在缓存之前加了一层校验。如果key 值不存在,就不会请求到我们的缓存更加不会到我们的数据库中。

布隆过滤器可以理解为一个不怎么精确的 set结构,当你使用它的 contains 方法判断某个对象是否存在时,它可能会误判。但是布隆过滤器也不是特别不精确,只要参数设置的合理,它的精确度可以控制的相对足够精确,只会有小小的误判概率。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在。即使误判不存在走到缓存和后端服务也是可以接受的。

微信图片_20220414192819.png

缓存雪崩

缓存雪崩是指缓存的部分节点不可用导致整个缓存体系甚至整个服务系统不可用

微信图片_20220414192824.png

那么你可能会有疑问,缓存雪崩和缓存击穿有什么关系呢?

从概念上来看,缓存击穿是因为查询不存在的 key 穿透缓存直接访问我们的数据库。而缓存雪崩是因为我们的缓存节点不可用,请求未经过缓存就直到了我们的数据库层面。然而两者都会影响我们的服务稳定性。

缓存节点的不可用会导致缓存雪崩,那么我们缓存组件集群部署是不是就解决了这个问题呢?

集群部署有两种情况:

  • 一种就是简单的主从例如 redis 的哨兵之殇
  • 采取一致性 hash 算法集群部署例如 redis 的分片集群

第一种情况:发送雪崩的时候一般是多个节点同时不可用,例如我们的节点服务器内容不足,虽然分主从节点都是存储的数据都是一样的。如果缓存中的数据过大导致节点不可用。那大部分节点也会存在这个问题。请求会大面积的落到数据库层面导致后端系统崩溃。

第二种情况:  首先看一下下图虽然数据根据会根据取模算法分配到不同的节点中,假设节点 A 不可用,数据 A 会按照逆时针找到节点 B,会因为本来应该存放到节点 A 的数据存放到节点 B,以此类推会导致整个缓存节点不可用。请求也会大面积落到我们后端的数据库层面导致系统崩溃。

微信图片_20220414192830.png

解决方案

  • 对缓存体系进行实时监控,当请求访问的慢速比超过阀值时,及时报警,通过机器替换、服务替换进行及时恢复。
  • 对缓存增加多个副本,缓存异常或请求 miss 后,再读取其他缓存副本。
  • ehcache 本地缓存 + Hystrix 限流&降级,避免 MySQL被打死
  • 业务 DB 的访问增加读写开关,当发现 DB 请求变慢、阻塞,慢请求超过阀值时,就会关闭读开关,部分或所有读 DB 的请求进行 failfast 立即返回,待 DB 恢复后再打开读开关。

数据不一致

数据不一致的概念很简单:就是缓存中的数据和数据库中的数据不一致

那为什么会不一致呢?我们的数据被缓存之后,一旦数据被修改(修改时也是删除缓存中的数据)或删除,我们就需要同时操作缓存和数据库。这时就会存在一个数据不一致的问题。

微信图片_20220414192834.png

如上图所示当我们先删除数据库再去操作缓存,缓存中未删除数据库其实已经不存在该数据了。这个时候就会出现缓存不一致的情况。

聪明的小伙伴肯定想到了我们还是需要先做缓存删除操作,再去完成数据库操作。则会去数据库中查询,如果缓存中没有该数据,则会去数据库中查询,之后再放入到缓存中。这样就完美了嘛?答案肯定不会这么简单。请看下图:

微信图片_20220414192838.png

解决方案

这里其实没有什么很完美的解决方法。可以将变更的 key 添加到安全队列中。当另一个查询请求 B 进来时,如果发现缓存中没有该值,则会先去队列中查看该数据是否正在被更新或删除,如果队列中有该数据,则阻塞等待,直到 A 操作数据库成功之后,唤醒该阻塞线程,再去数据库中查询该数据。这里其实也是有很多缺陷的。线程需要阻塞等待。

最好的解决方案就是如果数据更新比较频繁且对数据有一定的一致性要求,我通常不建议使用缓存。看到这里是不是发出了一句切!!!!

微信图片_20220414192846.png


 总结


缓存虽然能大幅度的提高服务器的性能以及用户的体验感。但是随着而来的就是各种由于缓存导致的一系列问题。

相关文章
|
7天前
|
机器学习/深度学习 自然语言处理 算法
分享爱,分享精彩瞬间,分享5款实用软件
分享爱,分享时光,分享精彩瞬间,大家好,我是互联网的搬运工,今天继续给大家带来几款好用的软件。
16 1
|
5月前
|
数据库
周末时光不浪费学起来
周末时光不浪费学起来
22 3
|
6月前
|
存储 编译器 C语言
【这个“数据在内存中的存储(1)”讲解我能吹一辈子】
【这个“数据在内存中的存储(1)”讲解我能吹一辈子】
42 0
|
12月前
|
C语言
我读书少,你们得帮帮我
我读书少,你们得帮帮我
|
JavaScript 小程序 Java
当年那个手搓CPU的老哥回来了!
当年那个手搓CPU的老哥回来了!
|
存储 JSON JavaScript
听说你情人节没人陪,这不我来给你介绍对象啦
听说你情人节没人陪,这不我来给你介绍对象啦
185 0
听说你情人节没人陪,这不我来给你介绍对象啦
|
存储 缓存 前端开发
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
|
缓存 安全 前端开发
今天520,要及时「缓存」你们的珍贵时光。(一)
在很久很久以前人类和洪水作斗争的过程中,水库发挥了至关重要的作用 : 在发洪水时可以蓄水,缓解洪水对下游的冲击;在干旱时可以把库存的水释放出来以供人们使用。这里的水库就起着缓存的作用。在如今互联网的世界里随着互联网的普及,内容信息越来越复杂,用户数和访问量越来越大,我们的应用需要支撑更多的并发量,同时我们的应用服务器和数据库服务器所做的计算也越来越多。
今天520,要及时「缓存」你们的珍贵时光。(一)
|
Java
学弟学妹们,学会霍夫曼编码后,再也不用担心网络带宽了!(2)
学弟学妹们,学会霍夫曼编码后,再也不用担心网络带宽了!
104 0
学弟学妹们,学会霍夫曼编码后,再也不用担心网络带宽了!(2)
|
算法 搜索推荐 程序员
学弟学妹们,学会霍夫曼编码后,再也不用担心网络带宽了!(1)
学弟学妹们,学会霍夫曼编码后,再也不用担心网络带宽了!
88 0
学弟学妹们,学会霍夫曼编码后,再也不用担心网络带宽了!(1)