只要你是程序员,就会知道什么是“缓存”。“缓存”,比如测试组小姐姐,运营组小姐姐,产品组小弟。但是缓存真的就这么简单,人人都能用吗?大家都知道,缓存可以让打开速度慢的页面变成“秒开”。您经常访问的几乎所有应用程序和网站都涉及缓存的使用。那么,除了加快数据访问速度之外,缓存还有什么作用呢?此外,任何事物都有两个方面。我们如何才能在避免其缺点的同时充分利用缓存的优势?文章从以下几个方面讨论缓存:1、缓存能做什么?2.哪里可以加缓存?3.缓存是灵丹妙药吗?1、缓存能做什么?当一个页面打开很慢的时候,你就会想到引入缓存,这样页面打开的速度会更快。其实,快与慢是相对的。从技术角度来说,缓存之所以快,是因为缓存是基于内存构建的,而内存的读写速度是硬盘的X倍,所以用内存代替用于读写的硬盘。自然媒体可以大大提高访问数据的速度。这个过程大致是这样的,通过将访问过的数据存放在内存中供后续访问,从而达到提速的效果。其实除此之外,还有另外两种重要的缓存使用方式,预读和延迟写。预读预读就是预读要加载的数据,也可以称为“缓存预热”。就是在系统对外提供服务之前,先将硬盘中的部分数据加载到内存中,再对外提供服务。之所以会这样,是因为有些系统一旦启动,就会有成千上万的请求进来,如果这些请求直接发给数据库,很有可能数据库的压力会急剧增加,直接阻塞和无法正常回复。为了缓解这个问题,需要通过预读来解决。你可能会问,即使你使用了缓存,你还是处理不了?那么就需要做横向扩展+负载均衡。如果说预读是在数据出口处加一个pre-buffer,那么顾名思义,下面要说的延迟写就是在数据入口后加一个post-buffer。延迟写入大家都知道数据库的写入速度是比读取速度慢的,因为在写入的时候有一系列的机制来保证数据的准确性。所以,要想提高写入速度,要么将数据库分表,要么使用缓存进行缓冲,然后一次性批量写入磁盘,以提高速度。由于分库分表操作对跨表操作和多条件组合查询的副作用巨大,引入它的复杂度远大于引入缓存。我们应该优先考虑引入缓存的解决方案。那么,通过缓存机制加速“写入”的过程,就可以称为延迟写入。就是把需要写入的数据预先写入磁盘或者数据库,暂时写入内存,然后返回成功。然后周期性地将内存中的数据批量写入磁盘。你可能认为写入内存就认为成功了。万一发生意外、断电、关机等导致程序异常终止,数据会不会丢失?是的。所以延迟写一般只用在对数据完整性要求不是那么严格的场景。比如点赞数、参与用户数等,可以大大缓解频繁修改数据库带来的压力。其实在大家熟知的分布式缓存Redis中,默认使用的持久化机制——RDB,也是同样的思路。在一个成熟的系统中,其实没有一个地方可以应用缓存。接下来Z哥就帮大家梳理一下我们可以在哪些地方“添加缓存”。我在哪里可以添加缓存?首先搞清楚一件事,我们要缓存什么?即满足什么特征的数据需要缓存?毕竟,添加缓存是一项额外的成本投资,而且物有所值。一般来说,可以用这两个标准来判断:热数据,访问频繁,比如每秒几十次;静态数据,很少变化,读远大于写,比如每隔几次变化一次天。然后你就可以找到一个合适的地方为他们添加缓存。缓存的本质是一种“防御”机制,系统之间的数据流动是一个有序的过程。因此,选择在何处添加缓存,就相当于在道路上选择在何处设置路障。可以保护路障后面的道路不被车辆碾过。那么,在从最终用户开始,到系统使用的数据库结束的路上,可以作为缓存建立点的位置大致如下。每个设置点都可以阻断一些流量,最终形成漏斗状的拦截效果,保护最后的系统和最终的数据库。下面简单介绍一下各个应用场景和需要注意的地方。浏览器缓存是离用户最近的可以作为缓存的地方,它使用的是用户的“资源”(缓存的数据在用户的终端设备上)。性价比最佳,让用户帮你分担压力。当你打开浏览器的开发者工具,看到fromcache或者frommemorycache,fromdiskcache,就说明数据已经缓存在用户的终端设备上(即使没有网络也可以访问)的一部分内容就是这个原因)。这个过程是浏览器帮我们完成的,一般用来缓存图片、js、css等。我们可以通过Http消息头中的Cache-Control对其进行控制,具体细节这里不再展开。js和cookie中全局变量的使用也属于这一类。浏览器缓存是用户端的缓存点,所以我们对它的控制要少得多。如果不发起新请求,则无法主动更新数据。提供CDN服务的CDN缓存服务商在全国乃至全球部署了大量的服务器节点(可以称为边缘服务器)。然后把数据分发到各地的这些服务器作为缓存,让用户访问就近服务器上的缓存数据,可以达到分压加速的效果。这在ToC类型的系统上特别有效。但需要注意的是,由于节点数量较多,更新缓存数据比较慢,一般至少在分钟级别。因此一般只适用于不经常变化的静态数据。还有一个解决办法,就是在url后面加一个自增数或者唯一标识,比如?v=1000。因为不同的url会被认为是“新”的数据和文件,会被重新创建。此处的网关(代理)缓存在您自己的站点上。很多时候我们会在源站的前面设置一层网关(或者反向代理,正向代理),为了做一些安全机制或者统一导流策略的入口。同时也是做缓存的好地方。毕竟网关是“业务无关”的,它能够屏蔽的请求,对于背后的源站也会有很大的好处,减少大量的CPU运算。常用的网关(代理)缓存包括Varnish、Squid和Ngnix。一般来说,nginx对于简单的缓存应用场景已经足够了,因为大部分时候我们会用它来做负载均衡,如果能少引入一项技术就可以降低复杂度。如果有大量的小文件,可以使用varnish,而squid相对大而全,运行成本也较高。请求的进程内缓存可以到这里来表明它是“业务相关的”,需要通过业务逻辑来操作。正因为如此,从这里引入缓存的成本相比前三种是大大增加的,因为缓存和数据库之间对数据一致性的要求更高。也许这是我们大多数程序员第一次刻意使用缓存。进程内和进程外缓存的使用有很多细节需要注意,这些后续文章会详细讨论。进程外缓存大家都不陌生,比如redis、memcached,甚至可以单独写一个程序来存放缓存数据,供其他程序远程调用。同样,我们稍后会在这里讲到细节。关于如何在redis和memcached之间进行选择,这里再提供一些建议。如果特别注重资源(cpu、内存等)的利用率,可以使用Memcached,但是程序在使用时需要容忍可能的数据丢失,因为它是纯内存机制。如果你不能忍受这个,而且你对资源利用比较大胆,可以用redis。而且redis的数据库结构比较多,而memcached只有key-value,更像是一个nosql的存储。数据库缓存数据库本身有自己的缓存模块,否则也称不上内存杀手。基本上,你可以吃多少你给多少内存。数据库缓存是数据库的内部机制,这里不赘述。一般都会给出设置缓存空间大小的配置,让你进行干预。最后,其实磁盘本身也有缓存。所以你会发现,为了让数据顺利写入物理磁盘,真是一波三折。不知道什么时候能有一个“快”的盘,让程序不用考虑缓存,来拯救我们的程序员。缓存是灵丹妙药吗?可能你觉得缓存这么好,越多越好,只要慢,就用缓存解决?再好的东西,也有不好的一面。缓存还有一系列的副作用需要考虑。除了上面提到的缓存更新和缓存-数据一致性问题,还有诸如:1.缓存雪崩2.缓存穿透3.缓存并发4.缓存无底洞5.缓存淘汰6....等问题。这些Z哥会在下一篇文章中和大家一起深入分析。总结好吧,让我们总结一下。这次IT技术研究院就为大家介绍缓存的三种使用方式。然后整理了一个完整系统中可以设置缓存的几个位置,分享了一些使用浏览器缓存、CDN缓存、网关(代理)缓存的经验。希望对你有所启发。IT技术研究院,专注互联网技术研究与分享,将经验传授给有梦想的人。
