ibcadmin 发表于 2019-10-24 09:48:57

缓存技术使用的实践思考分析




按照现在盛行的互联网分层架构模型,最简朴的架构当属Web相应层+DB存储层的架构。从最开始的单机肴杂摆设Web和DB,到厥后将二者拆分到不同物理机以制止共享呆板硬件带来的性能瓶颈,再随着流量的增长,Web应用变为集群摆设模式,而DB则衍生出主从机来包管高可用,同时便于实现读写分离。这连续串体系架构的升级,本质上是为了寻求更高的性能,到达更低的延时。<br />
<h2>缘起:为何利用缓存</h2>
<p>在应用对外提供服务时,其稳固性受到诸多因素影响,此中比较紧张的有CPU、内存、IO(磁盘IO、网络IO)等,这些硬件资源非常名贵,因此对于那些需要颠末复杂盘算才能得到结果的,大概需要频繁读取磁盘数据的,最好将结果缓存起来,制止资源的重复消耗。</p>
<p>CPU瓶颈</p>
<p>假如项目中有许多正则表达式盘算,大概某个盘算结果是多次中央结果归并后才得出的,且CPU的利用率不停居高不下,那么就可以考虑是否应该将这些结果缓存起来,根据特定Key直接获取Value结果,减少中央链路的转达过程,减少CPU的利用率。</p>
<p>IO瓶颈</p>
<p>众所周知,从磁盘获取数据受到磁盘转速、寻道速度、磁盘缓冲区巨细等诸多因素影响,这些因素决定了磁盘的IOPS,同时我们也知道对于数据的读写来说,CPU的缓存读写速度> 内存的读写速度>磁盘的读写速度。固然磁盘内部也配备了缓存以匹配内存的读写速度,但其容量毕竟是有限的,那么当磁盘的IOPS无法进一步提升的时间,便会想到将数据缓存到内存中,从而低沉磁盘的访问压力。这一战略常被应用于缓解DB数据库的数据访问压力。</p>
<h2>选择当地缓存和分布式缓存的考量点</h2>
<p>既然可以利用缓存来提升体系吞吐本领,那么紧接着碰到的问题就是选择当地缓存,照旧分布式缓存?什么时间需要利用多级缓存呢?接下来,让我们聊一聊在利用缓存优化项目的过程中,当地缓存和分布式缓存的应用场景和优缺点。</p>
<p>当地缓存的优缺点和应用场景</p>
<p>统一进程带来了以下优势:</p>
<ul>
<li>由于当地缓存和应用在同一个进程中,因而其稳固性很高,到达了和应用同生共死的田地;</li>
<li>由于在同一进程中,制止了网络数据传输带来的消耗,全部缓存数据直接从进程地点的内存地区获取即可。</li>


</ul>
<p>强耦合性也会导致以下这些劣势:</p>
<ul>
<li>当地缓存和应用共享一片内存,争抢内存资源,无法水平扩展,且大概造成频繁的GC,影响线上应用的稳固性。</li>
<li>由于没有持久化机制,在项目重启后缓存内数据就会丢失,对于高频访问数据,需要对数据举行预热操作。</li>
<li>多份进程内缓存存储着同样的数据内容,造成内存利用浪费。</li>
<li>同样的数据存储在不同的当地呆板,数据变化后,很难包管数据的一致性。</li>


</ul>
<p>结合以上优缺点,我们就会想到,假如有一种数据需要频繁访问,但一旦创建后就轻易不会改变,而且初始创建时就能预估占用的内存空间,那么这种范例的数据无疑是最适适用当地缓存存储了。</p>
<p>既然有了上述的应用场景,反观技术开辟中的诉求,发现其实许多良好的框架已经在如许利用了,比如缓存类class的反射信息,包罗field、method等。由于class的数量是有限的,且内容不会轻易改变,在利用时无需再利用反射机制,而只需要从当地缓存读取数据即可。</p>
<p>分布式缓存的优缺点和应用场景</p>
<p>优势:</p>
<ul>
<li>数据会合存储,消除冗余数据,办理团体内存的占用率,易于维护集群建缓存数据的一致性。</li>
<li>缓存中央件可以对缓存举行统一管理,便于水平扩容。</li>


</ul>
<p>劣势:</p>
<ul>
<li>依靠分布式缓存中央件稳固性,一旦挂了,轻易造成缓存雪崩;</li>
<li>由于是跨呆板获取缓存数据,因此会造成数据传输的网络消耗,以及一些序列化/反序列化的时间开销。</li>


</ul>
<p>对于上述缺点中,网络耗时等开销是不免的,而且这些操作耗费的时间在可担当范围内,而对于中央件的稳固性则可以通过服务降级、限流大概多级缓存思绪来包管。紧张看中的是它的长处,既然分布式缓存天然能包管缓存一致性,那么我们倾向于将需要频繁访问却又经常变化的数据存放于此。</p>
<h2>缓存框架利用过程的留意点</h2>
<p>岂论是当地缓存照旧分布式缓存,在利用缓存提升性能的时间,一定会考虑缓存掷中率的高低,考虑缓存数据的更新和删除战略,考虑数据一致性如何维护,本小节紧张针对以上的问题来分析不同实现方案的优缺点。</p>
<p>缓存掷中率</p>
<p>缓存掷中率不光是体系性能的一个侧面指标,也是优化缓存利用方案的一个紧张依据。缓存掷中率=哀求掷中数/哀求总数。接下来的多少缓存利用战略所围绕的焦点考量点就是在包管体系稳固性的同时,旨在提升缓存掷中率。</p>
<p>缓存更新战略<br /><br /></p>
<p>主动哀求DB数据,更新缓存</p>
<p>通过在集群中的每台呆板都摆设一套定时使命,每隔一段时间就主动向数据库DB哀求最新数据,然后更新缓存。如许做的长处是可以制止缓存击穿的风险,在缓存失效前就主动哀求加载DB数据,完成缓存数据更新的无缝毗连。</p>
<p>但如许做也增加了呆板的CPU和内存的占用率,由于纵然有多少Key的缓存始终不被访问,可照旧会被主动加载加载到内存中。也就是说,提高了业务抗风险本领,但对CPU和内存资源并不友爱。</p>
<p>详情可拜见下图,分布式缓存中存储着DB中的数据,每隔4.9s就会有定时使命执行去更新缓存,而缓存数据失效时间为5s,从而包管缓存中的数据永久存在,制止缓存击穿的风险。但对于Web哀求来说,只会访问k1的缓存数据,也即对于k2和k3数据来说,是无效缓存。</p>
<p><div align="center"></div><br /><br /></p>
<p>被动哀求DB数据,更新缓存</p>
<p>当有哀求到达且发现缓存没数据时,就向DB哀求最新数据并更新缓存。这种方案完全可以看做是方案一的互斥方案,它办理的是呆板CPU和内存浪费的问题,内存中存储的数据始终是有效的,但却无法制止缓存失效的瞬间又突然流量峰值带来的缓存击穿问题,在业务上会有肯定的风险。</p>
<p>详情见下图,缓存不会主动加载数据,而是根据Web哀求懒加载数据。对于哀求k1数据来说,发现缓存没有对应数据,到DB查询,然后放入Cache,这是通例流程;但假如有突发流量,大量哀求同时访问k2数据,但Cache中没有数据时,哀求就会同时落到DB上,大概压垮数据库。</p>
<p><div align="center"></div><br /><br /></p>
<p>缓存逾期战略</p>
<p>依靠时间的逾期战略</p>
<ul>
<li>定时删除</li>


</ul>
<p>对于需要删除的每个Key都配备一个定时器,元素超时时间一到就删除元素,释放元素占用的内存,同时释放定时器自身资源。其长处是元素的删除很及时,但缺点也很明显,比如为每个Key配备定时器肯定会消耗CPU和内存资源,严重影响性能。这种战略只适合在小数据量且对逾期时间又严格要求的场景能利用,一样平常生产环境都不会利用。</p>
<ul>
<li>惰性删除</li>


</ul>
<p>元素逾期后并不会立马删除,而是等到该元素的下一次操作(如:访问、更新等)才会判定是否逾期,执行逾期删除操作。如许的长处是节约CPU资源,由于只有当元素真的逾期了,才会将其删除,而不消单独管理元素的生命周期。但其对内存不友爱,由于假如多少已颠末期的元素不停不被访问的话,那就会不停占用内存,造成内存走漏。</p>
<ul>
<li>定期删除</li>


</ul>
<p>以上两种元素删除战略各有优缺点,无非是对CPU友爱,照旧对内存友爱。为告终合两者的长处,一方面减少了元素定时器的配备,只利用一个定时器来统一扫描逾期元素;另一方面加速了判定元素逾期的时间隔断,不是被动等候检测逾期,而是隔断一段时间就主动执行元素逾期检测使命。正是由于以上的改进点,此方案是元素逾期检测的惯常手段。</p>
<p>我们假设一个场景,为了保护用户隐私,通常在用户电话和商家电话之间,会利用一个假造电话作为沟通的桥梁。业务利用中,通常同一个假造号码在肯定时间内是可以对雷同的用户和商家创建毗连的,而当超出这个时间后,这个假造号码就不再维护映射关系了。</p>
<p>假造电话号码的资源是有限的,天然会想到创建一个假造号码资源池,管理假造号码的创建和释放。比如规定一个假造号码维持的关系每次能利用15分钟,那么逾期后要释放假造号码,我们有什么方案呢?</p>
<p>A. 方案一:全量数据扫描,依次遍历判定逾期时间</p>
<p><div align="center"></div><br /><br /></p>
<p>对于DB中存储的以上内容,天天记录都存储着假造号码的创建时间,以及颠末expire_seconds就会删除此记录。那么需要配备一个定时使命扫描表中的全部记录,再判定current_time - create_time >expire_seconds,才会删除记录。</p>
<p>假如数据量很大的环境,就会导致数据删除延迟时间很长,这并不是可取的方案。那是否有方案能直接获取到需要逾期的vr_phone,然后批量逾期来办理上述痛点呢?来看看方案二吧。</p>
<p>B.方案二:存储绝对逾期时间+BTree索引,批量获取逾期的vr_phone列表<br /><br /><div align="center"></div></p>
<p>将相对逾期时间expire_seconds改为记录逾期的时间戳expire_timestamp,同时将其添加BTree索引提高检索服从。仍然利用一个定时器,在获取待删除vr_phone列表时只需要select vr_phone from table where now()>=expire_timestamp即可。</p>
<p>对于空间复杂度增加了一个BTree数据布局,而基于BTree来考虑时间复杂度的话,对于元素的新增、修改、删除、查询的平均时间复杂度都是O(logN)。</p><br><br/><br/><br/><br/><br/>来源:<a href="https://www.cnblogs.com/winner192/p/11728858.html" target="_blank">https://www.cnblogs.com/winner192/p/11728858.html</a>
页: [1]
查看完整版本: 缓存技术使用的实践思考分析