美文网首页
缓存问题

缓存问题

作者: 人呆木水 | 来源:发表于2023-01-30 13:36 被阅读0次

缓存的本质

先聊一下缓存存储的基础。首先,局部性原理,是缓存存储的基础,即在局部的时间,对数据的访问是局部的、集中的(概率上去讲);另一个基础是,能快速提供数据访问的资源总是缺乏的,即如果所有数据都能被快速访问,那缓存即没有意义。

从本质上讲,即对数据计算的中间结果进行缓存,形成数据冗余,同样的输入的情况下,直接返回结果。比如在算法中,对于Add函数,输入相同的情况下,如果此函数没有副作用,那么输出也应该相同,那么,我们就可以建一个Map,存储结果,下次再有同样的数据需要计算,那么就直接查询出结果,而不用计算;再比如,数据库中,如果统计所有订单金额,即可以设计一个中间表,查询的话,直接访问中间表,而不用直接去统计数据,只需要在更新订单后,重新计算数据。

从Web服务的常用架构上来讲,一般请求进来以后,会从Web代理服务,到业务服务器,到数据库进行数据持久化,在业务服务器,可以在内存或者外部访问比较快的中间件中缓存数据。从架构上讲,一般可以对Http请求、SQL请求进行数据缓存,因为这两个是业务处理的边界,业务代理通过访问数据库,查询、修改数据,响应Http的请求。

综合来说,一般的机制如下:

  • 一个是透明缓存,即消费侧,不处理命中失效的情况,只是请求缓存,命中,则拿数据,没有命中,则挂起请求,由缓存处理器去请求生产端
  • 另一种是非透明的,即消费侧,先去找缓存数据,命中则取数据,不命中,则返回,由

建立一个模型,去判断缓存的意义。

CacheSize: 是缓存容量
QData: 指消息端去直接请求生产端, 产生一个功能的请求的代价
QCache: 指消息端去请求缓存端,产生一个成功/失败请求的平均代价
QCacheData: 指消息端去请求缓存端,请求失败,缓存端命中失败,触发访问生产端,并更新缓存的代价, 一般是QCache+DCache+UCache的代价的总和
UCache:指生产端更新缓存的代价
DCache:指缓存被标记失效的代价
CAP:指命中率

结合Web服务的架构, 我们假定读取访问缓存的代价与访问数据库的代价差了一个数量级,暂定为(访问的数学期望)10MS100MS

假定请求数为M,只读业务占有90%,如不使用缓存,所需要的代价为A = M*QData;如使用缓存,则有B = 10%M + 90%M * (1-CAP) * QData + 90%M * CAP * QCache ;故 N=B/A,则为缓存的期望效率。

缓存刷新的机制

缓存的失效有几种,适用于不同的场景。比如标记时间失效、主动标记失效、按算法清理(缓存空间一定)。主动标记失效,可以在业务执行前、也可以在业务执行后,但一般在业务执行后,因为业务层面本身事务性、有失败的情况。

缓存存储的KEY

KEY是查义缓存数据的关键,一般采用各种HASH算法。

几个边界情况

由于现实中,请求不是平均进到服务器的,所以有一个排队的情况,假定一个业务服务器,比如Tomcat业务服务器。我们假定Tomcat有500个线程,则同时最多可以进来500个请求,系统排队分别处理500个请求。同一时间(区间)的500个请求,有几种边界情况。

  • 全部打到缓存上,并全部命中
  • 全部打到缓存上,命中一部分,另一部分需要请求数据并刷新缓存
  • 部分打到缓存上,
    ** 部分打到缓存上(写请求无法打到缓存上),部分请求触发了数据更新,需要标记缓存数据失效

……

总之,请求进来以后,会触发上面定义的几种操作,命中、没命中、标记失效、刷新缓存,那第统计这些操作所付出的代价,与完全不使用缓存作为对比,则得出缓存的效率与解决方案。

在其它条件不变的情况下,缓存命中率,是影响系统处理请求所花费时间的主要因素。影响命中率的因素主要有缓存容量的大小、数据有效时间、访问集中度。缓存容量大,则可以缓存更多数据,命中率上长;数据有效时间短,频繁刷新缓存,原因可能是频繁修改数据(也有可能是缓存容量过小),则也会导致缓存命中率低;访问集中度,是决定缓存命中率的一个客观因素,访问集中度高,在同样的数据有效时间内,可以提高缓存命中率。

总之随着命中率的下降,系统处理请求期望时间也会变长,从而导致系统的QPS能力下降,(另一个影响是请求处理时间过长,导致请求处理的结果失效,消费端已经放弃接收结果)一旦QPS下降到一定程度,导致消费端请求失败,无法进入请求阶段,消费端频繁重新请求,没有熔断机制,则会导致系统崩溃。

导致请求的期望响应时间过长

会有几种极端的情况

一个是缓存全部失效,所有的请求打到数据库,那么系统能提供的QPS,就是拿掉缓存的系统,(当然,如果需要自动刷新缓存,还有自动刷新缓存的代价),如果打到系统上的QPS量过大,而没有熔断机制,则系统会被击溃。

无论如何,如果要保证系统能持续的提供服务,就要避免系统承载能力退化后,大量积压请求压到系统上,避免进入请求阶段的请求在相应的处理时间内处理完成(没有进入队列的,可以直接丢掉)。而决定一个请求处理时间的,则是对远程资源的访问,如数据库、RPC调用,对竞争资源的争取。

这里引出两个问题,一个是如何观察系统的响应时间,根据系统的响应时间判断系统的承载能力,另一个是系统内如何管理资源,如访问数据库的时间、RPC调用的时间、对竞争资源的争取的时间,避免因为业务处理时间过长,导致请求处理失效(处理了,但没有起有作用)而玩死自己。

无效请求带来的缓存击穿问题

如果缓存只是对正常的业务访问进行缓存,如查询每个用户的个人信息,系统如果只对返回有用户信息的请求进行缓存,而对没有用户信息为空的访问没有进行缓存,如果消息端持续攻击,则会降低缓存的命中率。
这个问题本质上是对空值的处理问题。

并发访问带来的重复刷新数据问题

如果一个业务,有多个请求同时进入到处理池,则有可能多个“业务处理”同时OR先后访问数据库,刷新缓存。可以使用同步锁,但也有开销。

服务异常带来的同时刷新数据问题(缓存雪崩)

由于刷新缓存也需要一定的代价,如果缓存失效过多(同时被标记失效),系统处理能力退化,给数据库访问/RPC访问/竞争资源访问带来问题。就是上面聊到的,如何协调内部资源,保证到业务处理队列的请求不要太多。

在一种典型的Web服务架构下,我曾经一种处理方式是限制业务服务器的Tomcat线程数,而对缓存的访问则使用Nginx+Lua的方式在Nginx端进行处理。本质上来说,是把请求队列放大一些,把处理业务的队列放小一些,从而从容的刷新数据。

缓存刷新对缓存的命中的影响,刷新机制也影响着缓存的命中率。缓存刷新是指从请求进到系统后,到系统可以为其它同类请求提供缓存访问的这个时间段。

访问数据:消息端去请求生产端,产生一个成功的请求

几个指标

几种缓存的方式,一种透明的,即代理。

使用缓存与使用数据结构优化访问速度的区别。

相关文章

  • 高并发与缓存

    本文主要讲述高并发下缓存会出现的问题。 在高并发下,缓存会出现的问题有:缓存一致性、并发问题、穿透问题、缓存的雪崩...

  • Redis第9课:缓存设计与优化

    我们将在这篇讨论以下七个问题。 缓存收益与成本的问题 缓存更新的策略 缓存颗粒的控制 缓存穿透的优化 无底洞问题的...

  • 缓存问题

    一、缓存更新策略 一般情况来说,缓存更新策略有三种: 先删除缓存,后更新数据库 先更新数据库,后更新缓存 先更新数...

  • 缓存问题

    两个要点: 关于Etag值的计算,Tornado是使用SHA1算法。 仅处理Get和Head请求中的Etag,对于...

  • 缓存问题

    1.缓存的产生 在Ajax的get请求中,如果运行在IE内核的浏览器下,其如果向同一个url发送多次请求时,就会产...

  • 缓存问题

    1.缓存穿透:请求访问了缓存中没有的数据,或者缓存宕机,导致请求直接查db。 解决办法:把没有的数据也缓存一分,但...

  • 缓存问题

    强制客户端刷新 location.reload(true) 是强制刷新,无论文档的最后修改日期是什么,它都会绕过缓...

  • 缓存问题

    用了缓存之后,有哪些常见问题? 常见的问题,可列举如下: 写入问题 缓存何时写入?并且写时如何避免并发重复写入? ...

  • 缓存问题

    缓存的本质 先聊一下缓存存储的基础。首先,局部性原理,是缓存存储的基础,即在局部的时间,对数据的访问是局部的、集中...

  • 缓存穿透、缓存并发、缓存失效之思路变迁

    在用缓存的时候,基本上会通用遇到以下三个问题: 缓存穿透 缓存并发 缓存失效 一、缓存穿透 上面三个图会有什么问题...

网友评论

      本文标题:缓存问题

      本文链接:https://www.haomeiwen.com/subject/sixphdtx.html