【读书报告】高性能网站建设指南

志扬工作室

共 10195字,需浏览 21分钟

 ·

2021-07-07 21:05

Start:关注本公众号后,可直接联系后台获取排版美化的详细文档!

Hints:本篇文章所编纂的资料均来自网络,特此感谢参与奉献的有关人员。


  • 序言A:前端性能的重要性

  • 后端优化内容:

编译器选项、数据库索引、内存管理

  • 关注前端性能优化的重要性:

1 关注前端可以很好地提高整体性能。如果我们可以将后端响应时间缩短一半,整体响应时间只能减少5%~10%,而如果关注前端性能,同样是将其响应时间减少一般,则整体响应时间可以减少40%~45%

2 改进前端通常只需要较少的时间和资源。减少后端延迟会带来很大的改动,例如重新设计应用程序的架构和代码,查找和优化临界代码路径,添加或改动硬件,对数据库进行分布化等。这些改动需要花费数周或数月。

3前端性能调整已被证明是可行的。

  • 性能的黄金准则:

只有10%~20%的最终用户响应时间花在了下载HTML文档上。其余的80%~90%时间花在了下载页面中的所有组件上。

 

  • 序言B:HTTP概述

  • HTTP的主要概念:

HTTP是一种客户端-服务器协议,由请求和响应构成。

  • B/S架构下,网站访问的完整过程:

用户:首次输入网站网址URL

浏览器:向特定URL发送HTTP请求

DNS服务器:域名解析,将特定的URL解析成匹配的IP地址

服务器:发回HTTP响应,Http响应包含状态码、头和响应体,同时响应文本中expires头明确指出浏览器是否可以使用组件的缓存副本来消除浏览器和服务器之间进行对页面是否更新检查的需要。

浏览器和服务器之间通过TCP建立持久连接.

浏览器:浏览器会解析HTML请求并开始下载页面中的组件。如果浏览器的缓存是空的,需要下载所有的组件HTML文档只占总响应时间的5%。用户需要花费其余95%的时间中的大部分时间来等待组件的下载,小部分时间在解析HTML、脚本和样式表。当浏览器看到响应中有一个expire头时,就会和相应的过期时间组件一起保存到缓存中。只要组件没有过期,浏览器就会使用缓存版本而不会进行http请求。

用户:在网站上跳转

浏览器:检查浏览器的缓存,查看是否已经存在缓存,如果缓存中的组件没有明确说明是否有效,浏览器就会向特定URL发送条件get请求

服务器:根据条件get请求,查看组件,返回组件的last-modified

  • 浏览器向服务器发送的请求类型:

GETPOSTHEADPUTdeleteoptionstrace

  • Http响应内容:状态码、头、响应体

压缩:

如果浏览器和服务器都支持的话,可以使用压缩来减少响应的大小。浏览器可以使用Accept-Encoding来声明它支持压缩。服务器使用Content-Encoding头来确认响应已被压缩。

条件GET请求:

如果浏览器在其缓存中保留了组件的一个副本,但不确定它是否仍然有效,就会生成一个条件GET请求。如果确认缓存的副本仍然有效,浏览器就可以使用缓存中的副本,这会得到更小的响应和更快的体验。基于响应中的Last-Modified头,浏览器可以知道组件最后的修改时间,它会使用If-Modified-since头将最后修改时间发送给服务器。如果组件自生成日期以来没有改变过,服务器会返回一个“304 Not Modified”状态码并不再发送响应体,从而得到一个更小且更快的响应。

Expires

条件Get请求和304响应有助于让页面加载的更快,但仍需要在客户端和服务器之间进行一次往返确认,以执行有效检查。Expires头通过明确指出浏览器是否可以使用组件的缓存副本来消除这个需要。

Keep-Alive:

持久连接的引入解决了多对一请求服务器导致的socket连接低效性的问题,它使浏览器可以在一个单独的连接上进行多个请求。浏览器和服务器使用connection头来指出对Keep-Alive的支持。

 

  • 第一章规则1-减少HTTP请求

只有10~20%的最终用户响应时间花在接收请求的html文档上。剩下的80~90%的时间花在html文档所引用的所有组件(图片、脚本、样式表、flash等)进行的http请求上。因此,改善响应时间的最简单途径就是减少组件的数量,并由此减少HTTP请求的数量。

  • 方法1:使用图片地图既能减少HTTP请求,又无需改变页面外观感受

实现效果:

未使用图片地图:

使用图片地图:

使用图片地图的缺陷:在定义图片地图上的区域坐标复杂

  • 方法2:使用css sprites ,将多个图片合并到一个单独的图片中

  • 方法3:内联图片

1内联为立即数    

data:URL 模式,允许将小块数据内联为立即数,数据就在其URL自身之中。但由于dataurl是内联在页面中的,在跨越不同页面是不会被缓存。


2 内联在样式表  

将内联图片放置在外部样式表增加了一个额外的HTTP请求,但被缓存后可以得到额外的收获。

内联在样式表的优点:

  • 方法4:合并脚本和样式表

将单独的文件合并到一个文件中,可以减少http请求的数量并缩短最终用户响应时间。将多个脚本合并为一个脚本,多个样式表合并为一个样式表。理想情况下,一个页面应该使用不多于一个的脚本和样式表。

页面大小和响应时间有着很强的正比关系。

减少组件的数量是最重要的一部,用文本替换图片会给该页面带来性能的最大改进。

 

  • 第二章规则2:使用内容发布网络

使用内容发布网络,在多个地理位置不同的服务器上部署内容。如果应用程序web服务器离用户更近,则一个http请求的响应时间将缩短。如果组件web服务器离用户更近,则多个http请求的响应时间将缩短。

内容发布网络CDN是一组分布在多个不同地理位置的web服务器,用于更加有效地向用户发布内容。在优化性能时,向特定用户发布内容的服务器的选择基于对网络可用度的测量。推荐使用CDN服务提供商。

有些需要最终用户使用一个代理来配置他们的浏览器,有的需要开发者使用不同的域名;修改他们组件的url。无论如何也不要使用http重定向来将用户指向本地服务器,这会使得web页面响应速度慢。 cdn 不仅缩短用户响应时间,还提供备份,扩展存储能力和进行缓存。

使用CDN注意问题:

 1响应时间会受到其他网站影响,无法直接控制组件服务器,需要服务器提供商协助。

 2 建议使用多家CDN服务器提供商。

 3 CDN用于发布静态内容,如图片、脚本、样式表和flash。提供动态html页面会引入特殊的存储需求---数据库连接,状态管理、验证、硬件和os优化,超出CDN的能力范围。

4 使用内容发布网络,CDN服务器的地理位置与用户的地理位置影响性能很大。

 

  • 第三章规则3:添加Expires头

-为组件添加长久的expires ,通过使用一个长久的expires头,使得图片、脚本和样式表可以被缓存,这会在后续的页面浏览中避免不必要的HTTP请求。

-expires 头可以用于图片、脚本、样式表和flash等组件。

-web服务器使用expires 头来告诉web客户端它可以使用一个组件的当前副本,直到指定的时间为止。

  • 浏览器利用缓存的方式:

1expires头使用一个特定的时间,它要求服务器和客户端的时钟严格同步,而且时间一旦落后,就需要立马更新。 

  2 cache-control使用max-age 指令指定组件被缓存多久

  •  使用浏览器缓存注意的问题:

组件在浏览器中缓存,会减少响应时间,但已经访问过网站的用户也不大可能获取最新的组件,因为前一个版本已经在浏览器中缓存了。为了确保用户能获取用户的最新版本,最有效的解决方案是修改其所有链接。这样,全新的请求可以将从原始服务器下载最新的内容,修改文件名即可更新。

 

  • 第四章规则4:压缩组件

-通过减少HTTP响应的大小来减少响应时间。如果HTTP请求产生的响应包很小,传输时间就会减少。使用gzip编码来压缩HTTP响应包,并由此减少网络响应时间。还可以删除注释和缩短URL  

-可以压缩HTML文档,脚本和样式表,也可以压缩xmljson。图片和pdf不应该压缩,因为他们本来就已经被压缩了。

-配置gzip时使用的模块取决于apache的版本。

gzipapache上的配置详见:http://www.schroepl.net/projekte/mod_gzip

-web服务器的响应中添加vary头,web服务器可以告诉代理根据一个或多个请求头来改变缓存的响应。由于压缩的决定是基于accept-encoding请求头的,因此需要在服务器的-vary响应头包含accept-encoding。当浏览器带着accept-encoding gzip访问代理时,接收到的死压缩过的内容,否则就不是压缩过的内容。

 -代理的边缘情形:默认情况下,ETag不能反映出内容是否被压缩,因此代理可能会想浏览器提供错误的内容。

 -web服务器配置进行简单的修改,压缩尽可能多的组件,就能显著改善页面的反应速度。


  • 第五章 规则5:将样式表放在顶部

HTML页面就是进度指示器,当浏览器逐步加载页面时,页头、导航栏,顶端logo等,所有这些都会等待页面的用户提供视觉反馈,有助于改善用户体验。

  • 进度指示条的三个主要优势: 为用户提供可视化回馈很重要。

1让用户知道系统没有奔溃

2指出用户大概需要多久,以便用户能够在漫长的等待中做些其他事情

3能够为用户提供一些可以看的东西,使得等待不再那么无聊

  • 样式表存放位置分析:

1 如果将样式表放在文档底部会导致浏览器阻止内容逐步呈现,这是因为浏览器在绘制页面元素时,会因为逐步读取底部的样式表而重新绘制页面,在页面没有固定时,浏览器会阻塞内容逐步呈现,直至页面样式稳定。

2 如果将样式表放在文档顶部,浏览器会逐步呈现页面内容,对于实际绘制内容的时间没有影响,但会给用户较好的体验。

  • 会导致白屏的情形:

1 在新窗口中打开

2 重新加载

3作为主页

  • 将样式表放在文档顶部的方式:


注意:一个style块可以包含多个@import规则,但@import规则必须放在其他规则之前。使用@import规则会导致组件下载时的无序性,会阻塞页面逐渐呈现。样式表在页面中的位置并不影响下载时间,但会影响页面的呈现。

 

  • 第六章  规则6:将脚本放在底部

 使用脚本时,对于所有位于脚本以下的内容,逐步呈现都被阻塞了。将脚本放在页面越靠下的地方,意味着越多的内容能够逐步地呈现。

 Http1.1规范建议浏览器从每个主机名并行地下载两个组件。默认情况下,IRFirefox都遵守这一建议。如果一个web页面平均地将其组件分别放在两个主机名下,整体响应时间可以减少大约一半。简单地使用DNS别名可以将组件分别放到多个主机名中。但增加并行下载数量并不是开销的,过多地下载反而会降低性能。

  • 在下载脚本时并行下载实际上是被禁用的:

原因之一:脚本document.write 会修改页面内容,浏览器会等待,以确保页面能够恰当地布局

原因之二:如果并行下载多个脚本,无法保证响应应是按照特定顺序到达浏览器的。

  •  脚本对页面的影响:

1脚本会阻塞对其后面内容的呈现

2脚本会阻塞对其后面组件的下载

如果脚本使用document.write 向页面中插入了内容,就不能将其移动到页面中靠后的位置。

使用延迟脚本,defer属性表明脚本不包含document.wirte,这样的脚本可以移到页面底部,不会影响页面呈现。

 

  • 第七章规则7:避免CSS表达式

css表达式频繁的求值使其得以工作,也导致CSS的表达式低下性能。

CSS表达式不仅仅会在页面呈现和大小改变时求值,当页面滚动,甚至用户鼠标在页面上移过时都会进行求值。

  •  避免CSS表达式的方法:

1创建一次性表达式

2 使用事件处理器取代CSS表达式

使用事件处理器来为特定的事件提供所期望的动态行为,避免了浏览器在无关事件发生时对表达式多次求值。

 

  • 第八章 规则8 使用外部JavaScript和CSS

有时候,内联会比外部快,因为外部需要承担多个HTTP请求带来的开销。但是更多情况下,因为JavaScriptCSS文件有机会就会被浏览器缓存起来,包含动态内容的HTML文档,通常不会被配置为可以进行缓存的,每次请求这样的HTML文档都要下载内联的JavaScriptCSS,会导致页面呈现较慢。使用外部文件提供JavaScriptCSS带来的收益会随着每用户每月的页面查看次数或每用户每会话产生的页面查看次数的增长而增加。

 

主页倾向于使用内联,内联JavaScriptCSS文件,页面加载速度更快,同时,一般网站主页在浏览器每次启动都会缓存,在浏览器结束时都会自动清空缓存。

 

对于多次页面查看中的第一次的主页,主页内联JavaScriptCSS,但又能为所有后续页面查看提供外部文件。这可以通过主页加载完成后动态下载外部组件来实现。这能够将外部文件放到浏览器的缓存中以便用户接下来访问其他页面。

JavaScriptCSS被加载到页面中两次,先是内联,然后是外部,由于下载两次,会出现双重定义,解决方法是将组件放到IFram中。

当用户第一次访问页面时,服务器发现没有cookie,于是生成一个内联组件的页面。然后服务器添加javascript来在页面加载后动态下载外部文件—javascriptcss,并设置cookie,下一次访问页面时,服务器看到cookie,就生成一个使用外部文件的页面。

如果用户重新打开浏览器,基于会话的cookie会消失,但组件依然会存在缓存中。这会使得页面加载javascriptcss 时出现,可以将cookie从基于会话的改为短期的(数小时或数天)。

 

  • 第九章 规则9:减少DNS查找

使用keep-alive和较少的域名来减少DNS查找

输入URLDNS服务器根据域名寻找指定的IP地址。在DNS查找匹配的IP地址完成之前,浏览器不能从主机名那里下载到任何东西。响应时间依赖于DNS解析器所承担的请求压力,用户与DNS解析器之间的距离和用户的带宽速度。

 DNS查找可以被缓存起来以提高性能,用户请求了一个主机名之后,DNS信息会留在操作系统的DNS缓存中,以后对于该主机名的请求将无需进行过多的DNS查找。

 查找返回的DNS记录包含了一个存活时间TTL,告诉客户端可以对记录缓存多久。

过短的TTL会使得DNS记录很快失效,过长的TTL值会使得服务器故障转移速度降低。

微软操作系统的DNS缓存由DNS client服务进行管理。

IE浏览器和firefox浏览器都会进行dns 缓存。

IE浏览器的DNS缓存由三个注册表设置控制—DnsCacheTimeoutKeepAliveTimeoutServerInfoTimeOut

 

一个持久的TCP连接(Keep-alive)会一直使用,直到其空闲1分钟为止。由于连接是持久的,因此无需DNS查找,另外Keep-Alive通过重用现有连接避免了重复的DNS查找。

确保服务器支持keep-alive,以减少用户导航到网站时所需的DNS查找。

主机名数量包括页面URL、图片、脚本文件、样式表、flash对象等的主机名。减少唯一主机名的数量可以减少DNS查找的数量,但会潜在减少页面中并行下载的数量。由于每个主机名可以并行下载两个组件,使用一个主机名既减少DNS查找的数量,有最大化了并行下载。

 

  • 第十章规则10:精简JavaScript

JavaScript源代码进行精简

JavaScript是一门解释型语言,是构建web页面的首选。当以快速原型为基准开发用户界面时,解释语言要优于其他语言。

javascript代码中移除不必要的字符以减少其大小,进而改善加载时间。在代码被精简之后,所有的注释以及不必要的空白字符(空格、换行、制表符)都将被移除。

混淆也会移除注释和空白,同时也会改写代码。作为改写的一部分,函数和变量的名字将被装换为更短的字符串,这时代码更加精炼,也难阅读。混淆是为了增加对代码进行反向工程的难度,但也提高了性能。

  • 混淆的缺陷:

1 混淆过程本身很有可能引入错误

2 混淆会改变javascript符号,因此需要对任何不能改变的符号进行标记,防止混淆器修改它们。

3经过混淆的代码很难阅读,使得在产品环境中调试更加困难。

  • javascript的精简工具:

JSMin DoJoCompressor

 

精简css也能带来加载性能的优化,CSS的精简在于移除注释和空白,合并相同的类,移除不使用的类,使用缩写(用#606 代替‘#660066’,移除不必要的字符串(用‘0’代替‘0px’

 

  • 第十一章 规则11:避免重定向

重定向用于将用户从一个URL重新路由到另一个URL

进行重定向的原因:网站重新设计、跟踪流量、记录广告点击、简历易于记忆的URL

web服务器向浏览器发送HTTP响应头时,浏览器会自动将用户带到Location 字段所给出的URL

HTML文档中的头包含的metarefresh标签可以在其content属性所自定的秒数之后重定向用户。


javascript也可以用于重定向,将document.location设置为期望的URL即可。

重定向会延迟整个HTML文档的传输,在HTML文档到达之前,页面中不会呈现出任何东西,也没有任何组件会被下载。

重定向最为浪费、发生得很频繁的是,URL的结尾必须出现斜线(/)而没有出现时。

例如:访问http//astrology.yahoo.com/astrology,允许自动索引,并且能够获得与当前目录相关的URL。这是因为浏览器在进行GET请求时必须指定一些路径,如果没有路径,就会简单地使用文档根(/,发生重定向。

 

与其让用户受额外HTTP请求,最好还是使用Alias, mod_rewrite,DirectorySlash和直接连接代码来避免重定向

 

  • 第十二章规则12:移除重复脚本

确保脚本只被包含1

重复脚本损伤性能的方式:1 不必要的HTTP请求 2执行javascript所浪费的时间

在页面中多次包含相同的脚本会使页面变慢

IE中,如果脚本没有被缓存,或在重新加载页面时,会产生额外的HTTP请求

FirefoxIE中,脚本会被多次求值。

  • 避免重复脚本的方法:

1HTML 页面中使用SCRIPT 标签

2PHP创建insertScript函数

  • 第十三章规则13:配置ETag

配置或移除Etag,从Etag中移除changenumber或完全移除ETag可以避免当数据已经位于浏览器缓存中时进行不必要的和低效的下载

通过最大化浏览器缓存组件的能力,减少呈现页面时所必需的HTTP请求的数量能加速用户体验。可以通过最大化浏览器缓存组件的能力来实现这一目标。

 

 Etag实体标签是web服务器和浏览器用于确认缓存组件的有效性的一种机制。

 

浏览器: ----URL HTTP 请求  --DNS域名解析  ---服务器

浏览器   首次下载组件,存储到缓存中

浏览器再次访问组件,发送一个条件GET请求,服务器发来组件的Expires 头,浏览器检查组件是否过期,没有过期,不产生HTTP请求,已经过期,产生HTTP请求

 

服务器在检测缓存的组件是否和原始服务器的组件匹配时,有两种方式

1 比较最新修改日期


2 比较实体标签

ETAG 的加入为验证实体提供了比最新修改日期更为灵活的机制。例如,如果实体依据user-agent accept-language 头而改变,实体的状态可以反映在Etag中。

 

Etag的缺陷:

当浏览器从一台服务器上获取了原始组件,之后,又向另外一台不同服务器发起条件GET请求时,ETAG是不会匹配的、对于拥有多台服务器的网站,ApacheIISETAG中嵌入的数据都会大大地降低有效性验证的成功率。如果在多台服务器上寄宿网站,而且使用的是具有默认Etag配置的ApacheIIS,用户将面对缓慢的页面,服务器会有很高的负载,消耗大量的带宽,代理不能有效地缓存缓存内容。Apache 可以从Etag中移除inode值,只留下大小和时间戳作为组件的EtagIIS中可以为所有服务器设置相同的ChangeNumber,保留文件的时间戳作为ETag。这样会提高多台服务器同一个组件匹配Etag的成功率。从Etag中移除changeNumber或完全移除Etag可以避免当数据已经位于浏览器缓存中进行不必要的和低效的下载。

 

  • 第十四章规则14:使Ajax可缓存

确保Ajax请求遵守性能知道,尤其应具有长的expires

ajax DHTML中使用的一项技术,客户端可以获取和显示用户请求的新信息而无需重新加载页面。

Ajax 层位于客户端,与web服务器进行交互以获取请求的信息,并与表现层交互,仅更新那些必要的组件。

尽管ajax请求不是可缓存的,其他性能指导原则都可以运用,如压缩响应,缩短域名查找时间,精简脚本,不使用重定向,移除ETag

 

  • 第十五章析构十大网站

响应时间的测量使用的是GomezWeb监视服务(http://www.gomez.com).这里的响应时间被定义为从请求初始化完毕到页面的onload事件被触发所经过的事件。

使用Firebug(http://www.getfirebug.com)分析各个页面中的JavaScriptCSS。它最强大的功能是能够调试JavaScript代码,不过这只是其中的一小部分功能。Firebug还提供了检查DOM,调整CSS、执行JavaScript和浏览页面HTML等功能。

用于分析页面性能的主要工具是YSlow(http://developer.yahoo.com/yslow).YSlow通过遍历页面的DOM找到页面中的所有组件,使用XMLHttpRequest找到每个组件的响应时间及HTTP响应头。这些信息,以及通过解析页面的HTML手机的其他信息一起用于针对每个规则进行评分。YSlow还提供了其他工具,包括页面组件的汇总和使用JSLint(http://jslint.com)对页面中所有JavaScript进行的分析。

 

  • 总结

         根据黄金性能准则,终端用户等响应时间更多花费在组件的解析以及下载上,如何减少组件的下载就成为优化网站性能的关键。

  • 1减少HTTP请求数量:

    1.1是减少组件的HTTP请求,可以同多个组件绑定一个URL

    1. 2避免多次重定向,其本质也是下降HTTP请求  

  • 2缩短HTTP的传输距离

     利用CDN优化

  • 3精简HTTP的传输内容

       3.1压缩组件

       3.2压缩javascript

       3.3压缩CSS

       3.4避免重复使用脚本

  • 4延长HTTP的有效期(即使得组件有效期延长)

          4.1 expires 头延长组件有效期

          4.2配置或移除ETag 使得组件有效识别成功率提高

  • 5改善用户体验

        5.1样式表放置在顶部

        5.2脚本放置在底部

  • 6减少网站内容的运算时间

       6.1 减少CSS运算

       6.2 减少javascript进行复杂操作

  • 7使得B与S之间的连接更快

       7.1使用较少域名,减少DNS查找

       7.2使用keep-alive,使得DNS有效期延长,减少DNS 

公众号二维码

End:如果有兴趣了解金融量化交易和其他数据分析的实用技术,欢迎关注本公众号

浏览 40
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报