前言很高兴认识大家。之前分享了很多,今天终于进入正题。因为之前一直在讲自动化运维,其实做了这么多年的运维,自动化运维我也没做过多少年。过去几年,很多公司在各个方面都增加了机器数量,规模大了才开始做自动化运维。今天的话题是高性能Web架构的缓存系统。之所以说这个系统,是因为作为运维工程师,经常会遇到网站访问速度很慢的情况。要解决这个问题,直接去找开发商,也不一定能解决问题。因为这个问题不仅仅是一个开发问题,这个问题涉及到浏览器从发送请求到响应请求的一系列问题。所有的地方都需要一点点琢磨,才能最终找到问题所在。一、了解Web缓存的知识体系1.1从HTTP请求入手我们从一个Http请求入手,先介绍一下环境。左边是我们的客户端浏览器,右边是我们的Web服务器。当然,Web服务器背后的整体架构是不同的。说。第一步,当用户的浏览器发出请求时,请求会通过网络到达Web服务器。这句话说明当一个数据包从客户端发送到Web服务器时,这个时间就是网络延迟时间。第二步,Web服务器处理请求并返回数据。如果是动态请求,我需要查缓存,查数据库,最后把请求返回给浏览器。这个时间就是响应时间。第三步,响应数据从Web服务器发送到客户端,这又是网络传输时间。第四步,用户浏览器接收数据,计算并在本地渲染。这个时间就是计算和渲染的时间。你的JS脚本不一样,渲染的时间也不一样,但是这个时间比较小。1.2处理数据的时间都去哪儿了?让我们看一下Web访问时间的主要方面。客户端请求从客户端发送到服务器,服务器响应,然后服务器返回给客户端。数据处理也有比较大的时间。我们来研究一下时间都到哪里去了,发送时间+传输时间+处理时间=响应时间。发送时间=数据量比特/带宽,传输时间=传输距离/传输速度,这是整个数据包的传输时间。目前网络的处理时间往往不是说不能优化,至少可以说我们普通的运维和开发接触这方面的比较少。可能还有很多针对网络传输优化的产品,这里就不展开讨论了。1.3如何缩短处理时间我们今天讨论如何缩短处理时间。由于返回的数据,我们可以通过各种方式解决。那么有很多方法可以缩短处理时间。比如可以提高服务器并发度,修改架构等,处理的方法有很多种。今天我们就来说说如何使用缓存来减少处理时间。这是今天的重点。正如我所说,从出来到***,网上都找不到完整的缓存,怎么办?自己写一个,我是按照浏览器的一个Http请求去***,把我经历过的缓存都做一遍。首先,用户层在浏览器中输入一个域名。这个时候第一步不是DNS解析。第一步是浏览器DNS缓存,比如谷歌、火狐,默认是60秒。没有严格的上下级,应用DNS缓存,操作系统DNS缓存,DNS缓存服务器。***解析出IP地址,然后去浏览器缓存。我们将讨论浏览器缓存协商的三种方法。然后请求继续向下到CDN代理缓存的代理层。然后请求会到web服务器,再到应用层,再到数据库,有数据库缓存,再到系统层。***访问硬盘上的某个文件,有系统级缓存。***说到物理层,访问硬盘上的某个数据,读写某个博客,这就涉及到物理层了。我们只包括读缓存,不包括写缓存。2、关于Buffer和Cache2.1Buffer和Cache是??什么?Buffer一般用于写操作,我们称它为writebuffer。为什么会有缓冲区?因为不同的计算设备有不同的速度,比如CPU可以直接写数据到硬盘吗?因为硬盘太慢了,CPU只能在内存里写,内存写硬盘。我们称之为缓存。缓存一般用于读操作。我们可以称之为读取缓存。我们把正常访问的数据放在离我们最近的地方,我们可以很快的检索到。2.2什么是Cache这是Cache的一个例子,也就是说CPU有三级缓存,三级Cache,然后是内存。现在不要考虑Cache和Buffer的区别。2.3什么是缓冲区?白色弧形区域为左转候车区。它的作用是:比如现在是红灯,但是我们的车可以越过stopline到左转等候区。等候区呈弧形,距离目的地更近,生活中的Buffer就是这样。我把车停在离目的地较近的地方,这样转弯的时候就可以马上掉头,而且可以转得更快,转得快可以减少道路拥堵。这就是Buffer的作用。2.4再次定义Buffer和Cache!在我们的电脑里也是一样的。CPU不能直接向硬盘写数据,因为硬盘太慢了,等不及了。这时候,我把内存中的数据写入并返回,然后将剩余的内存发送到硬盘写入。但是很多时候,我们并没有特别区分Buffer和Cache,因为很多领域会发现不仅有读缓存Cache的功能,还有写缓存Buffer的功能。所以你经常看到有些区域是Buffer的开头,或者统称为开头,这时候怎么区分呢?根据其功能的不同,区分是Buffer还是Cache。有的Cache只指读缓存,不具备Buffer的功能,有的Cache兼有Cache和Buffer。例如内存就是一个典型的例子。我们向内存写入数据,读取数据也是在内存中读取。这是一个典型的名词问题。那么很多时候我们不用纠结到底是Buffer还是Cache,怎么区分呢?我们可以通过其作用来区分:Cache一般用于读缓存,用于将经常读取的内容放入缓存中,下次读取同样的内容,直接从缓存中读取,提高读取性能。有多个级别。Buffer一般用于写缓冲,解决不同介质直接存储速度的差异,将数据写到一个比自己慢不了多少的中间区域然后返回,最后写到目标地址,提高写性能。缓冲也可以有多个级别。就像将内存写入硬盘也很困难,所以硬盘会使用缓存。我们都知道硬盘都会有Cache。这个Cache其实兼有Buffer和Cache的作用。因为写入数据只需要将数据写入硬盘,就会经过Cache区,读取数据。我们的许多预读函数也经过这个区域。该区域称为缓冲区开始或简称为开始。可以看到缓存和缓冲都可以有多层,也可以分层。我们很多做开发的应该都知道,分层设计是架构师最基本的设计方法。3、关于Cache3.1缓存存储位置的存储位置,我们还是站在Web架构的角度。在客户端,我的网页迟早会存储在客户端,用户不用发送请求直接打开。这时候就是浏览器缓存了。浏览器将我的缓存存储在用户客户端中,因此用户打开页面会非常快。内存,内存分为最快的本地内存,但是本地内存的容量是有限的,此时可以存在远程服务器内存。比如分布式缓存,其实就是远程服务器的内存。当然性能不如本地内存,因为需要通过网络传输。网络传输会耗时,影响性能。硬盘,本地硬盘是特有的,而远程服务器硬盘,比如我们使用的分布式软件系统,或者共享文件系统,就是典型的远程服务器硬盘。3.2内存文件存储的tmpfs介绍还有一种方式,像这样,存在于本地内存中。比如我们写一个应用程序,这个应用程序需要在本地内存中存储数据,开发起来很容易。比如运维,我有一些访问频率很高的数据,但是不能很快的放到内存中,这时候怎么办?其实Linux系统为我们提供了一个文件系统,可以将我们的数据直接存放在内存中,这就是tmpfs。如果你是老运维,你应该对这个很熟悉,因为你在运维工作了至少七八年,因为最早的时候基本都是用tmpfs。tmpfs是如何工作的?它把数据直接放在共享内存中,它是一种特殊的文件系统,我在这里做了一个案例。我们可以看到这个tmpfs是系统默认的,是32G,使用率是12k。这时候我只需要放81兆的文件,你马上就会发现dev/shm目录占用了81兆,可用内存从62237变成了62156,共享内存从42变成了123。此时一次,做一道小学计算题,可用内存显示我们放了81兆的文件占用了内存空间。然后是共享内存,可以证明我们的/dev/shm是被linux用来共享内存的,这是一个典型的case。3.4如何使用tmpfs进行内存文件存储如何使用这个tmpfs?直接#就可以了,当然你也可以设置不同的大小。使用tmpfs有什么好处?***,存储空间的设置和动态变化,放入时会增加,删除时会自动缩小。第二,速度。在武侠世界里,唯一不能破的就是快,因为那是记忆。第三,没有坚持,这是它的缺点也是优点。为什么是劣势?当机器重新启动时,数据丢失。为什么是优势?因为在某些场景下,重启机器会让他丢掉。这取决于你如何使用它。例如,如果我把缓存的数据放在这里,它会更快。如果想利用它的优势,保持持久化,方法有很多,只要每次都能实时同步数据即可。解决。另外我们做反向代理缓存,数据一定要放在磁盘上。这时候我们可以考虑使用tmpfs。还有tmpfs上的session文件,tmpfs上的socket文件等需要高性能读写的场景。3.5tmpfs在内存文件存储方面的优势对比为什么要讲这个呢?因为我们之前在一个案例中使用了tmpfs,是一个电商活动,刚好有一个内部需求,需要一个性能读写的场景。我们不得不不断地写作和阅读。这时候,我们考虑了很多其他的解决方案,结果发现I/O无法处理。这时候就想到了tmpfs,可以直接使用。也就是说Cache的存储位置带出了tmpfs。3.6Cache的几个重要指标这里是一道面试题。我们手机常用的一个功能,云备份,可以把你的图片和短信备份到云端。这样的功能需要CDN加速吗?为什么?我的手机短信是备份到云端,然后从别的手机上下载的。需要用CDN加速吗?其实答案很明确,不需要。当然其他的疑惑后面再说,刚才说了云备份的场景不是必须的,为什么呢?这涉及到缓存几个重要的特性。缓存效率,如果所有的缓存都没有效率,只会拖慢整个进程,为什么呢?因为加了缓存就相当于给数据的访问和读取加了一层路径,如果这条路径不行就会变慢,所以缓存效率是缓存的一个很重要的指标,可以解释为什么会有这样的需求不够用CDN加速是因为没有效率。只有我可以访问我的图片和短信。我将它们同步到云端。当我更换手机时,只有我可以下载它们。缓存失败率为0%。当然不需要CDN加速。但是还有一个场景可能需要,那就是云盘。但是,云盘有两种不同的场景。我们现在用什么同步数据到云盘,这个需要CDN加速吗?不一定,一般这种云盘是很智能的,下载的时候会判断你资源的热度。具体怎么做,因为没做过不知道,但是我们有类似的相关系统,可以对资源的热度进行打分。比如资源的热度很高,说明下载的人比较多。这个时候可以考虑放到CDN上。但是在存储的时候,还有很多存储功能比如校验,可能不上传等等,今天主要讲缓存,说的是读取缓存。这个时候可能需要CDN加速,但是不需要云备份场景。这是我们需要掌握知识才能掌握问题的最根本的地方。这时候无论我们做什么,你都会发现所有的问题都会迎刃而解。4、关于客户端优化4.1浏览器和DNS缓存当我们发送Http请求时,第一步是做DNS解析。这是GoogleChrome的屏幕截图,这是保存DNS缓存的地方。可以看到我访问了谷歌,访问的时间刚好是1分60秒。下面是浏览器DNS缓存。现在和HTML5一样,有一个新的特性叫做DNS航运区。这是京东的首页,可以看到很多链接。你是什??么意思?最常见的页面组件是图片等。先说一个前提,Http协议通常叫streaming,为什么呢?因为我边下载边渲染,浏览器会先请求web服务器获取整个HTML页面,浏览器会从上到下一行一行的读取。每次读取一行时,浏览器都会引发一个新线程来下载新的HTML页面。页面的页面组件资源下载后直接渲染。为什么我们打开网页很慢?问题1.网页被屏蔽时,网页打开缓慢。什么情况下会被封?加载JS的时候会被阻塞,会看到一个页面一直在转圈,JS被阻塞,因为JS可能会修改页面的路径数,所以加载JS的时候要等JS下载完再加载在继续下载之前执行。所以我们经常做网页优化的时候,会将CSS放在页面顶部,JS放在页面底部,因为JS下载会被屏蔽。问题2、为什么一个文件有多个域名?第二个问题,你可能会疑惑,为什么京东的一张图片值得10-30个域名?这是因为浏览器访问了一个网站。浏览器有并发限制,不可能单进程运行。一般不同版本像火狐可能有6-8个并发,但是并发是针对域名的,所以他开发了很多域名。,让页面打开更快。但是,如果域名太多,就会出现另一个问题。将有太多的DNS解析。这个时候怎么办?HTML5有一项新功能,称为DNS航运区。我可以先获取DNS解析,以后你用的时候直接用,不用再解析了。这些方法其实都是加快前端优化的手段,当然还有很多,比如减少页面组件,当然页面组件少点打开会更快。或者合并请求。比如我们做运维或者淘宝,支持组件合并,比如把一些小的CSS和JS合并在一起发送,这样会更快。如何优化,当然还有css背景偏移,很多小图标,我其实就是一张图片,我下载下来用背景偏移技术显示在页面上。还有懒加载,为了加快首屏时间,我用的是懒加载。我先加载首屏需要的资源,然后在鼠标向下拖动的时候一点点加载。这些方法是为了加快首屏时间或网页打开时间。当然,还有很多其他的DNS缓存。除了浏览器DNS缓存,其余都是系统文件。系统DNS缓存,到localDNS,localDNS也是一个有缓存的集群,所以每一级都是一个DNS缓存。很多情况下,比如你要更改某个DNS的A记录,我们会怎么做?我会提前把A记录的TTL生命周期时间改的很短,这样我改A记录很快。当然,做运维的人都会知道,国内有很多小运营商耍流氓,把DNS缓存设置的时间很短。龙,看了好几天设置了,所以修改完成后,有些小地方没有生效。DNS解析完成后,解析成公网IP地址,浏览器会向公网IP地址发起请求。当然涉及到网络传输,请求的网络传输,数据的网络传输。这个时候就涉及到了Http缓存行。客户端和服务器需要通过Http进行通信。我发了一个请求,告诉你服务器能不能用本地缓存,缓存有没有过期,服务器告诉他你可以用本地缓存。4.2关于浏览器缓存浏览器缓存协商有3种方法。首先,让我们看看浏览器缓存的位置。上图为Firefox浏览器,存储在内存和磁盘中。有时你会发现火狐浏览器会打开很慢,加载缓存,内存中有很多这样的数据。4.2.1基于Last-Modifiedh缓存协议先来看第一种缓存协商方式,基于最新修改时间的缓存协商,我们都知道默认所有系统都会有3次。我们有一个修改时间,所以我们所有的浏览器都非常聪明,默认情况下它们会使用SDNT系统调用来获取静态文件的修改时间。当你请求一个静态页面时,浏览器默认会返回给你这个页面的最新修改时间。第一次请求会发现是200,我们看看请求头,请求头,响应头。在responseheader中可以看到***修改时间是2016年,这是我的文件修改时间。浏览器默认情况下,将采用此时间。现在我点击刷新按钮,你会发现web服务器返回304,这是基于***修改时间的缓存协商。这个时候请求header请求的时候怎么请求呢?它会问浏览器,你告诉我这个页面保存修改了,你告诉我有没有改过,浏览器就告诉它,兄弟,这个页面没改过,你直接用本地缓存就可以了.这时候我们的web服务器不会向浏览器发送数据,浏览器可以直接使用本地缓存。但是你说动态还好,好吧,为什么呢?您可以伪造一个Http标头。那我为什么要讲这个,不是来开玩笑的。你需要了解客户端和浏览器是如何通过Http协议进行通信的。只要在返回的时候返回一个最新修改时间的header,就可以实现这个功能,不过这是浏览器的默认行为。4.2.2基于Etag缓存协议的第二种缓存协商方式,页面在最近修改时间频繁变化,但是内容没有变化。我的页面每次都重新生成,但是页面内容没有变化。如果是基于最新的修改时间,缓存就会失效。这时候会通过tagging通过不同的算法为页面计算出一个值,然后发送给浏览器。每次你问我这个值有没有变,但是每个浏览器这个算法都不一样。如果不太理解,可以理解为客户端的HTML5。每次用HTML5问我对不对,其实不是用HTML5加密的。以上两种缓存协商都有问题,因为要发起协商,我发给你,你再发给我。虽然没有生成任何数据,但至少我返回了一段数据,证明你要给我建立一个TCP三向握手和建立Http,消耗我的资源。4.2.3基于Expires的缓存协商Cedilla消除连接第三种缓存协商是基于过期时间。这个是给运维的,开发知道就够了。那么如果客户端和服务器时间不同步怎么办?事实上,浏览器非常聪明。它还有一个Cache-Control,它会计算一个本地的headertime,告诉你文件的生命周期有多长。不管你的客户端时间是否正确,你都可以正确使用过期时间。4.3你真的刷新了吗?如果我们有这些缓存,让我们看看我们是否会使用浏览器刷新。例如,Firefox浏览器有一个刷新按钮。当你按下刷新按钮时,此时基于***的修改时间和标记方式都会受到影响。但是基于不影响过期时间,所以很多时候我只需要设置一年过期,你狂点F5也没用。那么该怎么办?强制刷新,ctrl+F5强制刷新,此时浏览器会发起新的请求,不会使用任何缓存,所以看到很多前端开发人员不会使用刷新,感觉好尴尬,点了半天timekickin.我跑过去问运维,运维说你是怎么刷新的,F5,F5不行,需要ctrl+F5。这导致了另一个问题。比如我给某个资源设置了一年的过期时间,但是不到一年我想改怎么办?你总不能让我通知几千万用户按ctrl+F5吧。有几种方法,第一种是直接修改文件名,第二种是使用时间戳。当然,如果此时你还使用CDN,就要注意了。我们在配置CDN的时候,有两种。一种是URL有时间戳,一种是没有时间戳。缓存URL时,没有时间。戳,那就只能改名字了,要不就得在CDN上做个强制刷新,当然也是可以的,不是说不可以。如果做小系统,可以直接调用CDN刷新缓存,但是会比较费力。这取决于需求。5.关于工作的一些感悟,我看到在座的大家工作时间都变长了。可以想一想,工作时间越早、工作时间越长,回答问题的变化。我刚开始工作的时候,别人问我问题我马上回答,我直接回答说这是对的。工作久了,人家问我问题,问什么问题我不一定回答。为什么?这取决于你的需求,我的答案是针对不同的需求而不同的。所以后来人家说,你不确定monitor问的是什么。我说可以,以前学技术的时候,只需要做这个。当你了解的多了,你会发现其实不一定。我们开始学习的时候搞了一个负载均衡器。我认为这是一个集群。后来,一切都不一定了,还得看你的需要。更有什者,群里有人问,支持千万PV的班长是什么架构?“不确定”。不好说,看需求,你说一个小网站,就一个Http页面,支持几十亿PV没问题。所以这取决于你的业务类型。如果你谈论电子商务,那就很复杂了。电子商务的系统规模和整个业务都非常复杂,所以不同的业务有不同的结构。这里出现另一个问题。现在每个人都很难做自己的工作,为什么他们做起来难?不管你是做开发还是运维,现在互联网的开发都开始有场景了。你以前是做电商的,不管是开发还是运维。如果你加入游戏公司,你的薪水是不可能翻倍的,因为你的经验是不可复制的。你以前是做支付接口开发的,现在你跳转到网络商城,没有支付就完全不一样了。我们做运维也是一样,所以要不断学习,不学习只能慢慢被淘汰。
