如果这是第二次看到我的文章,欢迎文末扫码订阅我的个人公众号(跨界架构师)哟~
本文长度为3578字,建议阅读10分钟。
坚持原创,每一篇都是用心之作~
此前的「伸缩性」章节结束了,此文是「高性能」章节的第一篇。
只要是位正儿八经的程序员自然知道「缓存」是什么,甚至我司的很多做运营的小姐姐现在和程序员小哥哥的交流中都时不时冒出「缓存」字眼,让人压力山大。(本文讨论的「缓存」皆指的是软件层面运用的缓存)
大家都知道的一点是,缓存可以让原本打开很慢的页面,变得能“秒开”。你平时访问的APP、网站几乎都有涉及到缓存的运用。
那么,缓存除了能加速数据的访问之外,还有什么作用呢?
另外,任何事物都有两面性,我们如何才能将缓存的优点发挥得淋淋尽致,同时避免掉到它的弊端中呢?
Z哥今天想分享给你的就是我对缓存的理解和运用的思路,希望对你有所启发。
「缓存」能做什么?
正如前面所说,大家最普遍的理解就是当我们遇到某个页面打开很慢的时候,会想到引入缓存,这样页面打开就快了。
其实快和慢都是相对的,从技术角度来说,缓存之所以快是因为缓存是基于内存去建立的,而内存的读写速度比硬盘快X倍,所以用内存来代替硬盘作为读写的介质自然能大大提高访问数据的速度。
这个过程大致是这样的,通过在内存中存储访被问过的数据供后续访问时使用,以此来达到提速的效果。
其实除此之外,缓存还有另外2个重要的运用方式,「预读取」和「延迟写」。
预读取
预读取就是预先读取将要载入的数据,也可以称作「缓存预热」。就是在系统对外提供服务之前,先将硬盘中的一部分数据加载到内存中,然后再对外提供服务。
为什么要这样做呢?因为有些系统一旦启动就要面临上千上万的请求进来(在一些toC的项目尤其如此),如果直接让这些请求打到数据库上,非常大的可能是数据库压力暴增,直接被干趴,无法正常响应。
为了缓解这个问题,需要通过「预读取」来解决。
可能你会问,哪怕用了缓存还是扛不住呢?那就是做横向扩展+负载均衡的时候到了。(可以点击文末链接阅读之前的《弹性架构》系列)
如果说「预读取」是在「数据出口」加了一道前置的缓冲区的话,那么顾名思义,下面要说的「延迟写」就是在「数据入口」后面加了一道后置的缓冲区。
延迟写
你可能知道,数据库的写入速度是慢于读取速度的,因为写入的时候有一系列的保证数据准确性的机制。
所以,如果想提升写入速度的话,要么做分库分表,要么就是通过缓存来进行一道缓冲,再一次性批量写到磁盘,以此来提速。
题外话:由于分库分表对跨表操作以及多条件组合查询的副作用巨大,所以引入它的复杂度远大于引入缓存,我们应当优先考虑引入缓存的方案。
那么,通过缓存机制来加速“写”的过程就可以称作「延迟写」。就是预先将需要写入到磁盘或者数据库的数据,先暂时写入到内存,然后就返回成功。再定时将内存中的数据批量写入到磁盘。
可能你会想,写到内存就认为成功,万一中途出现意外、断电、停机等导致程序异常终止的情况,数据不就丢了吗?
是的。所以,「延迟写」一般仅用于对数据完整性要求不是那么苛刻的场景。比如点赞数啊、参与用户数啊等等,可以大大缓解对数据库频繁修改所带来的压力。
其实在我们熟知的分布式缓存Redis中,其默认运用的持久化机制——RDB,也是这样的思路。
在一个成熟的系统中,能够运用到缓存的地方其实并不是一处。下面Z哥就来帮你梳理一下我们在哪些地方可以“加缓存”。
哪里可以加「缓存」?
在说哪里可以加缓存之前我们先搞清楚一个事情,我们要缓存什么?也就是符合什么特点的数据才需要加缓存?毕竟加缓存是一个额外的成本投入,得物有所值。
一般来说你可以用这两个标准来判断:热点(被高频访问,如几十次/秒以上)数据、静态(很少变化,读远大于写,如几天变更一次)数据。
接下去就可以替它们找到合适的地方加缓存了。
缓存的本质是一个“防御性”的机制,而系统之间的数据流转是一个有序的过程。所以,选择在哪里加缓存就相当于选择在一条马路的哪个位置设路障。在这个路障之后的道路都能受到保护,不被车流碾压。
那么在以终端用户为起点,系统所用的数据库为终点的这条道路上可以作为缓存设立点的位置大致有以下这些。
每个设立点可以挡掉一些流量,最终形成一个漏斗状的拦截效果,以此保护最后面的系统以及最终的数据库。
下面Z哥来简要描述下每一个的运用场景以及需要注意的点。
浏览器缓存
这是离用户最近的可以作为缓存的地方,而且借助的是用户的“资源”(缓存的数据在用户的终端设备上),性价比可谓最好,让用户帮你分担压力。
当你打开浏览器的开发者工具,看到from cache或者from memory cache、from disk cache的时候,就意味着这些数据已经被缓存在了用户的终端设备上了(没网的时候也能访问到一部分内容就是这个原因)。
这个过程是浏览器替我们完成的,一般用于缓存图片、js、css这些。我们可以通过Http消息头中的Cache-Control来控制它,具体细节这里就不展开了。
js里的全局变量、以及cookie等运用也属于该范畴。
浏览器缓存是在于用户侧的缓存点,所以我们对其的掌控力就差很多,在没有发起新请求的情况下,你无法主动去更新数据。
CDN缓存
提供CDN服务的服务商,在全国甚至是全球部署着大量的服务器节点(可以叫做「边缘服务器」)。
那么将数据分发到这些遍布各地服务器上作为缓存,让用户访问就近的服务器上的缓存数据,就可以起到压力分摊和加速效果。这在ToC类型的系统上运用,效果格外显著。
但是需要注意的是,由于节点众多,更新缓存数据比较缓慢,一般至少是分钟级别。所以一般仅适用于不经常变动的静态数据。
题外话:解决方式也是有的,就是在url后面带个自增数或者唯一标示,如?v=1001。因为不同的url会被视作“新”的数据和文件,被重新create出来。
网关(代理)缓存
到这里做缓存就是在你自己的地盘了。很多时候我们会在源站前面架一层网关(或者说反向代理、正向代理),为的是做一些安全机制或者统一分流策略的入口。
同时这里也是做缓存的一个好场所。毕竟网关是“业务无关性”的,它能够拦下来的请求,对背后的源站也是很大的受益,减少了大量的CPU运算。
常用的网关(代理)缓存有Varnish,Squid,Ngnix。一般情况下,简单的缓存运用场景,用nginx即可,因为大部分时候我们会用它来做负载均衡,能少引入一个技术就少一份复杂度嘛。如果是大量的小文件可以使用Varnish,而Squid则相对大而全,运用成本也更高一些。
进程内缓存
一个请求能走到这里说明他是“业务相关”的,需要经过业务逻辑的运算。
也正因为如此,从这里开始对缓存的引入成本比前面3种大大增加,因为对缓存与数据库之间的「数据一致性」要求更高了。
可能我们大多数程序员第一次刻意使用缓存的场景就是这个时候。进程内和进程外的缓存运用中有很多的细节需要注意,这些也是我们后续文章的内容,所以我们后续再详聊。
进程外缓存
这个大家也熟悉,就是redis、memcached之类,甚至也可以自己单独写一个程序来专门存放缓存数据,供其他程序远程调用。
同样,这里的细节我们后续再聊,这里先多说几句关于redis和memcached该怎么选择的建议。
对资源(cpu、内存等)利用率格外重视的话可以使用Memcached,但程序在使用的时候需要容忍可能发生的数据丢失,因为是纯内存的机制。如果无法容忍这点,并且对资源利用率也比较豪放的话可以使用redis。而且redis的数据库结构更多,Memcached只有key value,更像是一个nosql存储。
数据库缓存
数据库本身自带缓存模块的,否则也不会叫它内存杀手,基本上你给多少内存就能吃多少。
数据库缓存是数据库的内部机制,我们这里就不深入下去了。一般都会给出设置缓存空间大小的配置来让你进行干预。
最后,其实磁盘本身也有缓存。所以你会发现,为了让数据能够平稳的写到物理磁盘中真的是一波三折,不知道什么时候可以有“快”到不需要程序来考虑缓存的磁盘出现来拯救我们程序员呢。
「缓存」是Silver bullet吗?
可能你会想缓存那么好,那么应该多多益善,只要慢就上缓存来解决?
一个事物看上去再好,也有它负面的一面。缓存也有一系列的副作用需要考虑。除了上面提到的「缓存更新」和「缓存与数据的一致性」问题,还有诸如:
-
缓存雪崩
-
缓存穿透
-
缓存并发
-
缓存无底洞
-
缓存淘汰
-
...
等等问题,这些Z哥会在接下去的文章中和你一起深入剖析。
想第一时间了解这些的可以「关注」Z哥一波~
总结
好了,我们总结一下。
这次呢,Z哥先向你介绍了运用缓存的三种思路。
然后梳理了在一个完整的系统中可以设立缓存的几个位置,并且分享了关于浏览器缓存、CDN缓存、网关(代理)缓存的一些使用经验。
希望对你有所启发。
后续的文章我将着重深入「进程内缓存」和「进程外缓存」的最佳实践,等我再次出现。
相关文章:
作者:Zachary
出处:https://www.cnblogs.com/Zachary-Fan/p/smalltarget.html
如果你喜欢这篇文章,可以关注下我的个人公众号哦。
▶关于作者:张帆(Zachary,个人微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。欢迎扫描下方的二维码~。
定期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些思考。
如果你是初级程序员,想提升但不知道如何下手。又或者做程序员多年,陷入了一些瓶颈想拓宽一下视野。欢迎关注我的公众号「跨界架构师」,回复「技术」,送你一份我长期收集和整理的思维导图。
如果你是运营,面对不断变化的市场束手无策。又或者想了解主流的运营策略,以丰富自己的“仓库”。欢迎关注我的公众号「跨界架构师」,回复「运营」,送你一份我长期收集和整理的思维导图。
相关推荐
1. BaseCache :为缓存数据最终存储的处类,默认为 PerpetualCache,基于Map存储 2. EvictionCache :当缓存数达到一定
淘宝的分布式文件存储引擎,简称TFS(Taobao File System),是阿里巴巴集团为解决大规模电商网站数据存储问题而设计的一款高性能、高可用的文件系统。它主要服务于淘宝内部的大量在线业务,如商品图片、用户数据等...
最终,银行选择了自主研发的方式,这其中包括对分布式缓存、消息中间件、分布式数据库等关键技术的深度研究和验证。在与支付宝、京东、华为、浪潮等公司交流后,民生银行构建了自己的分布式技术平台,完成了性能验证...
分布式对象存储是一种大规模、高可用、可扩展的数据存储系统,主要设计用于存储和检索大量非结构化数据,如图片、视频、文档等。在互联网时代,这种技术是支撑云服务和大数据应用的基础。《分布式对象存储——原理 ...
现在一些.NET开发人员开始放弃ASP.NET内置的缓存机制,转而使用Memcached——一种分布式的内存缓存系统。当运行在单独的Web服务器上,你可以很容易地清除一个已经确认被改变了的缓存。可惜,ASP.NET没有一个很好的...
分布式中间件依赖——咖啡汪项目启动依赖包(全) 咖啡汪推荐————使用RabbitMQ进行邮件发送,并确保发送成功(源码在github上,需要的自行下载哦) 咖啡汪推荐————使用Redisson组件,缓存映射MapCache进行...
分布式系统设计是现代互联网服务和企业级...以上是分布式系统设计中的核心知识点,理解和掌握这些概念对于构建可扩展、高可用的分布式系统至关重要。在实际工作中,还需要不断学习和实践,以应对不断变化的技术挑战。
分布式系统缓存设计 分享。分布式系统缓存设计 分享。分布式系统缓存设计 分享
本文主要详情大型分布式系统中缓存的相关理论,常见的缓存组件以及应使用场景。缓存概述缓存概述缓存的分类缓存主要分为四类,如下图:缓存的分类CDN 缓存CDN(Content Delivery Network 内容分发网络)的基本原理是...
分布式系统是计算机科学中的一个重要领域,它涉及到多个独立计算节点通过网络进行通信和协作,以完成共同的任务。《分布式系统概念与设计(第5版)》是一本深入探讨这一主题的经典教材,它提供了全面的理论知识和实际...
本课件"分布式系统PPT"可能涵盖了以下几个核心知识点: 1. **分布式系统基本概念**:讲解分布式系统的基本组成元素,如节点、网络、通信协议等,并介绍其与集中式系统的区别。分布式系统的核心特性包括透明性、一致...
接着,分布式系统的关键组件和技术包括:负载均衡、分布式数据库、分布式缓存、消息队列、服务发现和注册、分布式锁等。负载均衡是将任务分配到多个节点以平衡负载,提高效率;分布式数据库解决了单个数据库无法处理...
分布式缓存的实现,包括如何提供完整的分布式缓存来利用多机内存能力;消息队列的实现,包括如何实现发送和接收模式;分布式文件系统的实现,包括如何像操作本地文件一样操作远程文件,并利用多机硬盘存储能力;...
分布式系统是计算机科学中的一个重要领域,它涉及到多个独立计算节点通过网络进行通信和协作,以完成共同的任务。这本书“分布式系统-原理与范例”可能是深入理解这一主题的关键资源,尽管这里提供的信息是英文版且...
在IT行业中,Java语言因其平台无关性、丰富的库支持以及高效性能,在构建大型分布式系统方面扮演着重要角色。本文将深入探讨大型分布式系统中的Java...理解和掌握这些知识点,对于开发和维护高效的分布式系统至关重要。
分布式系统是现代信息技术领域中的核心概念,它涉及多个计算节点通过网络进行协同工作,共同处理任务,实现数据共享和计算能力的扩展。《分布式系统概念与设计 原书第5版》是一本深入探讨这一主题的经典教材,旨在...
《大规模分布式系统架构与设计实战》从作者的实战经验出发,深入浅出地讲解了如何建立一个Hadoop那样的分布式系统,实现对多台计算机CPU、内存、硬盘的统一利用,从而获取强大计算能力去解决复杂问题。一般互联网...
分布式系统原理与范型是计算机科学中的一个重要领域,它涉及到多台计算机协同工作,共同处理一个任务或数据,以提供高可用性、可扩展性和性能优化。这些课件旨在为学习者提供一个全面且系统的分布式系统知识框架。...
【描述】"PHP实例开发源码——SK美女图片伪静态缓存版 v1.0"表明这是一个特定版本的代码库,可能是开发者在某个时间点打包的稳定版本,便于用户下载和研究。这里的“SK美女图片”可能是一个图片集合或者一个在线图片...