柯南君教你如何对待大型网站平台的性能优化.docx
- 文档编号:15078307
- 上传时间:2023-06-30
- 格式:DOCX
- 页数:35
- 大小:34.02KB
柯南君教你如何对待大型网站平台的性能优化.docx
《柯南君教你如何对待大型网站平台的性能优化.docx》由会员分享,可在线阅读,更多相关《柯南君教你如何对待大型网站平台的性能优化.docx(35页珍藏版)》请在冰点文库上搜索。
柯南君教你如何对待大型网站平台的性能优化
柯南君:
教你如何对待大型网站平台的性能优化?
之五---web前端性能优化策略(长篇总结)
从企业架构上(见
①业务架构:
是把企业的业务战略转化为日常运作的渠道,业务战略决定业务架构,它包括业务的运营模式、流程体系、组织结构、地域分布等内容。
②IT架构:
指导IT投资和设计决策的IT框架,是建立企业信息系统的综合蓝图,包括数据架构、应用架构和技术架构三部分。
从企业IT架构体系上来看,特别是对于Web2.0网站来说,必须考虑的就是可扩展性:
随着使用人数的增多,能够及时的扩展IT系统的能力。
解决这个问题,通常有两种解决方式:
Scaleup和Scaleout,两种扩容的方式:
分别从两个维度来解决数据库压力。
这些不是本篇文章考虑重点;
本篇更多讲的是IT架构的性能调优-《web前端性能调优策略-内容篇》
一般来说,性能优化也就是下面的几个策略:
用空间换时间。
各种cache如CPUL1/L2/RAM到硬盘,都是用空间来换时间的策略。
这样策略基本上是把计算的过程一步一步的保存或缓存下来,这样就不用每次用的时候都要再计算一遍,比如数据缓冲,CDN,等。
这样的策略还表现为冗余数据,比如数据镜象,负载均衡什么的。
用时间换空间。
有时候,少量的空间可能性能会更好,比如网络传输,如果有一些压缩数据的算法,这样的算法其实很耗时,但是因为瓶颈在网络传输,所以用时间来换空间反而能省时间。
简化代码。
最高效的程序就是不执行任何代码的程序,所以,代码越少性能就越高。
关于代码级优化的技术大学里的教科书有很多示例了。
如:
减少循环的层数,减少递归,在循环中少声明变量,少做分配和释放内存的操作,尽量把循环体内的表达式抽到循环外,条件表达的中的多个条件判断的次序,尽量在程序启动时把一些东西准备好,注意函数调用的开销(栈上开销),注意面向对象语言中临时对象的开销,小心使用异常(不要用异常来检查一些可接受可忽略并经常发生的错误),……等等,等等,这连东西需要我们非常了解编程语言和常用的库。
并行处理。
如果CPU只有一个核,你要玩多进程,多线程,对于计算密集型的软件会反而更慢(因为操作系统调度和切换开销很大),CPU的核多了才能真正体现出多进程多线程的优势。
并行处理需要我们的程序有Scalability,不能水平或垂直扩展的程序无法进行并行处理。
从架构上来说,这表再为——是否可以做到不改代码只是加加机器就可以完成性能提升?
总之,根据2:
8原则来说,20%的代码耗了你80%的性能,找到那20%的代码,你就可以优化那80%的性能。
下面的一些东西都是我的一些经验,我只例举了一些最有价值的性能调优的的方法,供你参考,也欢迎补充。
(一)web前端性能优化策略
1.web前端优化最佳实践之内容篇(雅虎团队经验:
网站页面性能优化的34条黄金守则)
1)尽量减少HTTP请求(MakeFewerHTTPRequests)
HTTP请求:
作为第一条,可能也是最重要的一条。
根据数据分析,有很大一部分用户访问会因为这一条而取得最大受益。
有几种常见的方法能切实减少HTTP请求:
①合并文件比如把多个CSS文件合并成一个;
备注:
可以参见
②CSSSprites利用CSSbackground相关元素进行背景图绝对定位;
备注:
可以参见CSSSprites简介以及优缺点
③图像地图参见CSSSprites:
ImageSlicing‘sKissofDeath;
备注:
可以参见CSSSprites图片地图
④内联图像使用data:
URLscheme在实际的页面嵌入图像数据;
备注:
可以参见内联地图
2)减少DNS查找(ReduceDNSLookups)
①了解DNS,以及如何查找DNS?
在浏览器中打开一个网站对于大多数用户来说是很简单的事情,输入网址,回车,网站就打开了。
但是对于网站开发者来说,就在这短短一秒不到的时间里,发生了很多事情,DNS查找,建立连接,服务器处理,下载结果,客户端渲染等等。
在这里,我们着重对DNS查找讨论一下。
简单来说DNS查找就是将域名翻译成具体IP地址的过程,因为IP地址才是一台电脑在互联网上的唯一地址,域名只是用来方便人们记忆网站地址的名称而已,我们不会通过身份证号去记住一位朋友,而是他的名字。
DNS是通过一个分布式数据库系统维护的,系统下有很多节点,每个节点就是域名服务器,顶层是根域名服务器。
对于DNS查找的原理在这里只是大概说一下;
查找DNS是需要花费时间的,经验的总结是至少需要20毫秒左右的时间。
在此期间,浏览器是无法下载其他任何内容资源的。
所以浏览器会想办法对DNS查找的结果进行缓存。
而除了浏览器的缓存之外,操作系统(如windows)也会对DNS进行缓存,只不过浏览器太过于频繁,目前的主流浏览器都是使用自己的独特的缓存,而不使用操作系统的缓存
②如何减少查找DNS?
减少来自不同域请求数量的方法有很多,比如,将css和javascript文件合并,在图片处理时尽可能使用csssprites(参见上边“尽量减少HTTP请求”)技术,将小图片合并到一张大图,尽量将外部域的对象下载到本地服务器上等等。
总之原则就是,页面打开时DNS查找次数越低,页面打开速度越快。
A)IE中默认情况下对DNS的缓存时间为30分钟。
关于如何配置,可以通过阅读这篇文章了解更多信息。
B)Firefox默认的DNS缓存时间据说为1分钟,如果不满意这个选项,直接修改network.dnsCacheExpiration即可。
C)GoogleChrome默认的DNS缓存时间,据我观察也是1分钟,可以通过chrome:
//net-internals/#dns这个地址查看。
那么,讲了这么多,了解这个只是对于我们网站设计和优化有何启示呢?
A)由于DNS查找是需要时间的,而且它们通常都是只缓存一定的时间,所以应该尽可能地减少DNS查找的次数。
B)减少DNS查找次数,最理想的方法就是将所有的内容资源都放在同一个域(Domain)下面,这样访问整个网站就只需要进行一次DNS查找,这样可以提高性能。
C)但理想总归是理想,上面的理想做法会带来另外一个问题,就是由于这些资源都在同一个域,而HTTP/1.1中推荐客户端针对每个域只有一定数量的并行度(它的建议是2),那么就会出现下载资源时的排队现象,这样就会降低性能。
D)所以,折衷的做法是:
建议在一个网站里面使用至少2个域,但不多于4个域来提供资源。
我认为这条建议是很合理的,也值得我们在项目实践中去应用。
虽然大多数浏览器都可以缓存域名,即把域名和IP对应存储在本地,这样在打开网站时如果网址已经存在本地缓存中时直接从缓存中读取即可,不需要再进行远程DNS查询。
但是,一个网站上往往会有成百上千的对象,javascipt,css,图片,ajax请求等等,这些对象可能来自不同的域,就算下载这些对象的时间很快,但是因为数量多,累加起来就足以引起用户的注意了。
因此减少打开网站时的请求数量就是提高网站性能的有效办法。
3)避免跳转
跳转是使用301和302代码实现的。
下面是一个响应代码为301的HTTP头:
HTTP/1.1301MovedPermanently
Location:
Content-Type:
text/html
①浏览器会把用户指向到Location中指定的URL。
头文件中的所有信息在一次跳转中都是必需的,内容部分可以为空。
不管他们的名称,301和302响应都不会被缓存除非增加一个额外的头选项,
如Expires或者Cache-Control来指定它缓存。
②元素的刷新标签和JavaScript也可以实现URL的跳转,但是如果你必须要跳转的时候,最好的方法就是使用标准的3XXHTTP状态代码,这主要是为了确保“后退”按钮可以正确地使用。
但是要记住跳转会降低用户体验。
在用户和HTML文档中间增加一个跳转,会拖延页面中所有元素的显示,因为在HTML文件被加载前任何文件(图像、Flash等)都不会被下载。
有一种经常被网页开发者忽略却往往十分浪费响应时间的跳转现象。
这种现象发生在当URL本该有斜杠(/)却被忽略掉时。
例如,当我们要访问/apple时,实际上返回的是一个包含301代码的跳转,它指向的是/apple/(注意末尾的斜杠)。
在Apache服务器中可以使用Alias或者mod_rewrite或者theDirectorySlash来避免。
③连接新网站和旧网站是跳转功能经常被用到的另一种情况。
这种情况下往往要连接网站的不同内容然后根据用户的不同类型(如浏览器类型、用户账号所属类型)来进行跳转。
使用跳转来实现两个网站的切换十分简单,需要的代码量也不多。
尽管使用这种方法对于开发者来说可以降低复杂程度,但是它同样降低用户体验。
一个可替代方法就是如果两者在同一台服务器上时使用Alias和mod_rewrite和实现。
如果是因为域名的不同而采用跳转,那么可以通过使用Alias或者mod_rewirte建立CNAME(保存一个域名和另外一个域名之间关系的DNS记录)来替代。
4)可缓存的AJAX
Ajax经常被提及的一个好处就是由于其从后台服务器传输信息的异步性而为用户带来的反馈的即时性。
但是,使用Ajax并不能保证用户不会在等待异步的
JavaScript和XML响应上花费时间。
在很多应用中,用户是否需要等待响应取决于Ajax如何来使用。
例如,在一个基于Web的Email客户端中,用户必须等待Ajax返回符合他们条件的邮件查询结果。
记住一点,“异步”并不异味着“即时”,这很重要。
为了提高性能,优化Ajax响应是很重要的。
提高Ajxa性能的措施中最重要的方法就是使响应具有可缓存性,具体的讨论可以查看AddanExpiresoraCache-ControlHeader。
其它的几条规则也同样适用于Ajax:
①Gizp压缩文件
②减少DNS查找次数
③精简JavaScript
④避免跳转
⑤配置ETags
让我们来看一个例子:
一个Web2.0的Email客户端会使用Ajax来自动完成对用户地址薄的下载。
如果用户在上次使用过Emailweb应用程序后没有对地址薄作任何的修改,而且Ajax响应通过Expire或者Cacke-Control头来实现缓存,那么就可以直接从上一次的缓存中读取地址薄了。
必须告知浏览器是使用缓存中的地址薄还是发送一个新的请求。
这可以通过为读取地址薄的AjaxURL增加一个含有上次编辑时间的时间戳来实现,例如,&t=11900241612等。
如果地址薄在上次下载后没有被编辑过,时间戳就不变,则从浏览器的缓存中加载从而减少了一次HTTP请求过程。
如果用户修改过地址薄,时间戳就会用来确定新的URL和缓存响应并不匹配,浏览器就会重要请求更新地址薄。
即使你的Ajxa响应是动态生成的,哪怕它只适用于一个用户,那么它也应该被缓存起来。
这样做可以使你的Web2.0应用程序更加快捷。
5)LazyLoad推迟加载内容(按需加载内容)
①页面加载过程,都需要加载什么?
页面加载过程中,除了页面本身的内容外,可能需要加载很多额外的资源,例如我们常说的:
A)脚本
B)样式表
C)图片
这一原则的核心是:
延迟加载或者按需加载
②你可以仔细看一下你的网页,问问自己“哪些内容是页面呈现时所必需首先加载的?
哪些内容和结构可以稍后再加载?
把整个过程按照onload事件分隔成两部分,JavaScript是一个理想的选择。
例如,如果你有用于实现拖放和动画的JavaScript,那么它就以等待稍后加载,因为页面上的拖放元素是在初始化呈现之后才发生的。
其它的例如隐藏部分的内容(用户操作之后才显现的内容)和处于折叠部分的图像也可以推迟加载
③常用到的延迟加载方式
A)针对脚本的加载
我们可以想象一下,一个真正的网站项目中,会有各种各样的脚本文件,其中还包含很多基础的框架(例如jquery,knockoutjs等),这些脚本文件可能都或多或少需要在页面中引用。
问题在于,如果页面一多起来,或者复杂起来,我们可能不太能准确地知道某个页面是否真的需要某个脚本。
(难道不是这样吗?
),一个蹩脚的解决方案是,那么就在母版页中,一次性将所有可能用到的框架脚本都引用进来吧。
你是这样做的吗?
如果这样做的话,对于小的项目来说,没什么问题,但是对大项目尤其是产品来说,尤其是,小步快跑,不断迭代的产品来说,简直是毁灭性的,后期将会有大量的,瘦身工作,否则,会影响整个产品的性能(柯南君深有体会)!
【案例分析】
a)当一个网站有很多js代码要加载,js代码放置的位置在一定程度上将会影像网页的加载速度,为了让我们的网页加载速度更快,本文总结了一下几个注意点:
1、延迟加载js代码
备注:
①JS延迟加载方案,一般情况下都是用setTimeout来实现,这样通过延迟加载js代码,给网页加载留出更多的时间
[javascript]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
pre"> pre"> pre">setTimeout("document.getElementById('my').src='include/common.php';",3000);//延时3秒 pre"> ②JS最后加载方案,在需要插入JS的地方插入以下代码: [html]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 pre"> [html]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 pre"> pre">当然,那个LOADING…你可以换成自己喜欢的小图片。 看起来很有AJAX效果呢。 然后在页面最底端插入: [html]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 pre"> [html]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 pre"> ③让JS最后加载方案二,这个牵涉到网页的加载顺序问题,例如引入外部js脚本文件时,如果放入html的head中,则页面加载前该js脚本就会被加载入页面,而放入body中,则会按照页面从上倒下的加载顺序来运行javascript的代码~~~所以我们可以把js外部引入的文件放到页面底部,来让js最后引入,从而加快页面加载速度。 B)针对图片的加载 原理是这样: 页面可见区域以下的图片先不加载,等到用户向下滚动到图片位置时,再进行加载。 这样做的好处在哪里? ——当页面有好几屏内容时,有可能用户只看前几屏的内容,这样我们就可以只加载用户需要看的图片,减少服务器向用户浏览器发送图片文件所产生的负荷。 于是我打开了土豆网,没发现它的这种功能。 但是一想,这确实是挺有意思的。 这跟人人网的分批加载新鲜事的有异曲同工之妙。 【案例分析】 a)Lazyload延迟加载效果与ImagesLazyload图片延迟加载效果 备注: ①Lazyload是通过延迟加载来实现按需加载,达到节省资源,加快浏览速度的目的。 ②这个Lazyload主要特点是: 支持使用window(窗口)或元素作为容器对象; ③对静态(位置大小不变)元素做了大量的优化; ④支持垂直、水平或同时两个方向的延迟。 请参见延迟加载效果展示之Lazyload延迟加载效果 ImagesLazyload图片延迟加载效果 在这里要感谢cloudgamer的贡献 b)以下是简单的HTML和JS——在IE下简单测试过了。 [html]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN"> -- center"mce_style="text-align: center"> 1290px;width: 800px;border: 1px;background: gray;">
150px;width: 800px;border: 1px;background: green;">
scripttype="text/javascript"> -- vartemp=-1;//用来判断是否是向下滚动(向上滚动就不需要判断延迟加载图片了) window.onscroll=function(){ varimgElements=document.getElementsByTagName("img"); varlazyImgArr=newArray(); varj=0; for(vari=0;i if(imgElements[i].className=="lazy"){ lazyImgArr[j++]=imgElements[i]; } } varscrollHeight=document.body.scrollTop;//滚动的高度 varbodyHeight=document.body.offsetHeight;//body(页面)可见区域的总高度 if(temp for(vark=0;k varimgTop=lazyImgArr[k].offsetTop;//1305(图片纵坐标) if((imgTop-scrollHeight)<=bodyHeight){ lazyImgArr[k].src=lazyImgArr[k].alt; lazyImgArr[k].className="notlazy" } } temp=scrollHeight; } }; //-->
script>