您的位置:首页 > Web前端

web前端优化

2010-12-26 22:15 197 查看
Web优化已经越趋成熟,不再那么扑朔迷离。在这里,我们跟据一些优化实践准则应用于perfgeeks,并进行了记录。Pefgeeks的系统软
环境是CentOS5.3 + Apache2.2.3 + Wordpress2.9。优化的工作方式,一般都是:快照 + 分析 + 变更 +
快照。让我们开始吧…



看到这份快照,我们就可以形成一个最简单的统计:

1,请求数量:8 = 5 + 2 + 1 (5个图片、2个CSS文件、1个html文档)

2,发送包大小: 3400bytes

3,响应包大小: 146081bytes

4,页面加载时间: 10.296秒

合并外置Javascript文件或CSS文件

我们通过快照1的观察,很容易发现这里一共加载了二个CSS文件。其中codesnippet.css文件很小,1kb都不到。并且,该文件用于文本代码
高亮显示插件codesnippet。而高文本代码高亮显示,几乎每个页面都会用到(考滤到这是一个技术blog)。所以,我们准备把
codesnippet.css合并到style.css这个文件中去。并且把插件用于加载该css文件的代码行注释掉。然后,我们再来观察结果




看到这份快照,我们可依然可以形成一个统计:

1,请求数量:7 = 5 + 1 + 1 (5个图片,1个CSS文件,1个html文档)

2,发送包大小:3032bytes。我们会发现总体而言发送包的大小变小了,这是因为我们少发了一个http请求。但是细心的朋友会观察到第一个
http请求包从367bytes增加到了403bytes,这是为什么呢?这是因为请求包中多了Cookie数据。用户端通过http请求头
Cookie将用户端的Cookie数据传给服务端。

3,响应包大小:145635byes。我们图片请求大小都没有变化,而第一个请求index.php稍微有点变化,这是一个动态资源请求,有点小波动是
正常地。我们最关心的是style.css这个响应,它的响应数据包变大了。主要是因为把codesnippet.css合并到了style.css这个
文件,所以,这个http响应body部分变大了。7547 + 971 = 8518
(约等于8259),大于8259是正确地,因为还要减去codesnippet.css响应头部大小。

4,页面加载时间:10.446秒。这里时间没有变化,反而加大了,是因为网络的问题。

Expires浏览器缓存服务端响应

浏览器总会把最近访问资源的响应拷贝一份存放在客户端本地,我们称之为缓存对象
。如果下一次访问的时候,该缓存对象还是新鲜的,则浏览器不会向服务端发出
请求,而是直接渲染给用户。判断本地拷贝(即缓存对象)是否过期过状态,还是保鲜状态。浏览器会通过用户端本地时间与缓存对象的Expires时间相比
较,如果还没有到达Expires时间,则认为对象是新鲜的,没有过期。
Expires时间,由web服务器响应的时候指定
。Apache2可以使用mod_expires模块设置Expires时间。操作如下:

#lsof -p `cat /var/run/httpd.pid` |grep mod_expires

httpd 16554 root mem REG 8,3 9660 784296 /usr/lib/httpd/modules/mod_expires.so

我们查看发现,当前httpd守护进程加载了mod_expires模块。如此,我们可以配置Apache,设置静态资源(image/*, text/css, text/javascript)响应都在用户端缓存一个月。

<IfModule mod_expires.c>

ExpiresActive On

ExpiresByType image/* "access plus 1 month"

ExpiresByType text/css "access plus 1 month"

ExpiresByType text/javascript "access plus 1 month"

ExpiresByType application/x-javascript "access plus 1 month"

</IfModule>





这次的产生的效果很明显,我们明显可以看到,页面加载时间明显降低了。静态资源部分都被缓存(cache)了,所谓Cache就是指请求包大小为0,响应
包大小为0。这意味着,用户端根本没有向服务器发出http请求。这里看到所花费有时间,是浏览器解析渲染缓存对象给用户所花费的时间。注意,这里变化很
明显地一个地方是http响应状态由200变成了Cache。我们知道,httpd响应状态是不包括Cache的,所以这里的Cache应该是
HttpWatch输出,表示使用缓存对象。我们也可以从响应头里面确认Expires时间与响应时间相差正是1个月。





gzip压缩文本类型http响应

我们常常使用zip,
gzip,zlib等工具来压缩我们的文本文件。同样的,我们可以使用gzip来压缩类型为text的http响应数据包。Gzip可以让整个http响
应缩小大约66%。自Apache2开始,Apache开始默认安装

deflate.so模块,
虽然名称上是deflate,但实际上还是使用了
gzip。操作如下

# lsof -p `cat /var/run/httpd.pid ` |grep deflate

httpd 15223 root mem REG 8,3 17916   784291 /usr/lib/httpd/modules/mod_deflate.so

可以知道,当前运行的httpd守护进程已经加载了mod_deflate模块。http.conf配置如下

<IfModule mod_deflate.c>

SetOutputFilter DEFLATE

SetEnvIfNoCase Request_URI /.(?:exe|t?gz|zip|iso|tar|bz2|sit|rar)$  no-gzip dont-vary

SetEnvIfNoCase Request_URI /.(?:gif|jpe?g|jpg|ico|png)$  no-gzip dont-vary

SetEnvIfNoCase Request_URI /.pdf$ no-gzip dont-vary

SetEnvIfNoCase Request_URI /.flv$ no-gzip dont-vary

BrowserMatch ^Mozilla/4 gzip-only-text/html

BrowserMatch ^Mozilla/4/.0[678] no-gzip

BrowserMatch /bMSIE !no-gzip !gzip-only-text/html

Header append Vary User-Agent env=!dont-vary

</IfModule>

上面的配置忽略
了二进制、图片、PDF, FLV等次源请求的压缩。我们提过,主要压缩
的还是响应体类型为文本类型
的http响应。




我们再来观察快照的变化。最大的变化是第一个响应体大小从40142bytes降低到了10883bytes,而另一个text/css类型的响应
style.css,则从合并后的8259bytes压缩到了2723bytes。用户端接受到的总体大小也从145635byes降到了
111200byes。

精简Javascript和CSS脚本

我们知道,JavaScript和CSS代码都是客户端解析的,而文件却存放在服务端。所以,对于js和css文件,用户端浏览器总是通过http协议把
js和css文件下载到用户端本地,浏览器再解析js和css文件。对于访问用户而言,javascript和css这些专业概念,应该保持透明。所以,
聪明的开发者就会使用精简工具将js和css精简到最小,让下载速度更快。我们推荐yuicompress来精简你的js和css代码。并且,我在这里写
了一个脚本,帮助项目发布的时候自动化精简js和css。



#!/bin/sh

#@file yc.sh

src_path

="/var/www/vhosts /perfgeeks.com/wp-content/themes/perfgeeks"

out_path

="/tmp/output"

yui_compress_tool

='/opt/tools/yuicompressor-2.4.2.jar'

is_ok

=1

 

#make the output directory

if

[

!

-d

"$out_path

"

]

; then

mkdir

-p

"$out_path

"

if

[

$?

-ne

0 ]

; then

echo

"the $out_put

was not existed"

exit

fi

fi

 

find

"$out_path

"

-type

f -print

|

xargs

rm

-rf

for

ext in

`

echo

"css js"

`

; do

for

f in

`

find

"${src_path}

"

-name

"*.$ext

"

-type

f `

; do

dest_path

="${out_path}

`dirname $f`

"

filename

=`

basename

$f

`

if

[

!

-d

"$dest_path

"

]

; then

mkdir

-p

"$dest_path

"

fi

java -jar

"$yui_compress_tool

"

$f

-o

"${dest_path}

/${filename}

"

--type

"$ext

"

if

[

$?

-ne

0 ]

; then

is_ok

=0

exit

fi

done

done


我们观察可以知道,这里只有一个style.css需要精简。我们将精简后style响应与精简之前的快照进行对比。




在这里,我们比较可以,虽然变化不是很大,但还是可以看得出style.css响应包还是变小了。这里变化很小主要是因为:我们
style.css被我们的前端工程师精简过一次,这次精简的部分只是合并过去的codesnippet.css那部分代码。不然,精简js和css脚本
文件带来的变化应该会更大,尤其是大型网站。

优化图片资源:压缩图片

一个页面的组件用得最多的除了js和css外,还有图片。而且图片资源比较大,也是最占页面下载时间的。我们可以通过一些工具来无损压缩图片资源


。使图片
类型的响应体缩小,达到缩短页面加载的时间。JGEG格式图片我们推荐jpegtran,而PNG格式图片我们推荐工具OptiPNG。我们将jgp压缩
后,再来观察一下相应快照。





通过与第一个快照对比,我们很容易地发现kubrickbg-ltr.jpg响应14206bytes缩小至2151bytes。还有二个图片文件响应也变小了不少。

精简请求包:清除不必要的Cookie

浏览器总会在每次发出响应的时候,将该domain有效的Cookie记录通过http头Cookie字段发给服务端。比如,传递session
id等等。这就是说Cookie记录越多,请求包就越大,而一般的MTU大小是1500bytes
,过大的httpd请求数据包会导致分包传输。一个域并行两个下载。
对于静态
资源请求而言,我们是不需要用到Cookie的,而只有动态内容请求才有可能用到Cookie。所以,我们可以通过主机别名、虚拟目录或虚拟主机的方式将
静态资源分开。比如,这里我们使用http://static.perfgee.com来负责静态资源请求,而将动态内容资源请求通过http:
//www.perfgeeks.com作为请求url。httpd守护进程配置如下:

<VirtualHost 222.73.211.215:80>

ServerAdmin liaowq.box@gmail.com

DocumentRoot /var/www/vhosts/perfgeeks.com

ServerName static.perfgeeks.com

#ErrorLog /var/log/httpd/static.perfgeeks.com-error.log

TransferLog /var/log/httpd/static.perfgeeks.com-access.log

</VirtualHost>

同时,还要设置一下wordpress静态内容访问url,修改wp-conf.php,将以下内容加到/wp-conf.php

define (‘WPLANG’, ‘zh_CN’);

#define (‘COOKIE_DOMAIN’, ‘www.perfgeeks.com’);

define (‘WP_CONTENT_URL’, ‘http://static.perfgeeks.com/wp-content’);





相较于上一次的快照而言,除了第一个请求之外,其它的请求包大小略有减小。请求包的总体大小而言从5432bytes减小至4344bytes,也减小了1KB。对于大型网站而言,这一准则优化效果更让人喜悦。

持久连接:Keep-Alive

KeepAlive保持连接
,它是一个什么概念呢?我们知道httpd的传输协议是TCP协议。TCP在传输之前,必须发送三个数据包建立连接,这也就是
著名的TCP三次握手连接

,
同时结束传递的时候,需要发送四个数据包断开连接
,这正是著名的TCP四次挥手

。这意味着每个http请求与响应都要进行三次
握手和四次挥手,一共来回7个数据包。7个http请求除http产生的网络数据包之外,还有49个数据包需要发送。Keep-Alive机制就是将第一
个http请求建立的连接留给后面几次http请求、响应数据包使用,并且让第一次连接关闭延迟到最后一次http请求响应结束后才关闭。这样,我们所有
请求就只要处理7个数据包,省下了42个数据包。Apache的KeepAlive启用配置如下:

KeepAlive On

MaxKeepAliveRequests 100

KeepAliveTimeout 10

这三个配置参数的意思,就是启用KeepAlive机制,自启用机制开始与该用户端建立的TCP连接供给10秒内数据包传输使用。也就是说,自第一个
http请求建立了tcp连接后,10之内用户端发生的请求就不用像第一个请求一样,不需要去建立tcp连接了,而是借用第一个http请求建立的连接来
传输http网络数据协议包,直到10秒以后,该连接才会关闭。我们的实例可以看出,该用户请求一次页面,共有7个http请求,花费时间大概在5之内。
做为一个blog网站,一般用户会连接请求二个页面,即首页打开文章,并会在文章查看页面停留很长一段时间。也就是说,用户最有可能在10秒之内发送一堆
请求,之后的很长一段时间不会再发送请求了。这一节,我们没有快照,有兴趣的朋友可以通过tcpdump查看整个过程。KeepAlive的缺点在保持连
接的时候,连接会占用内存

(socket也是一种文件类型)

ETag有必要吗?

自http1.1开始支持ETag
功能,ETag其实就是Last-Modified补充机制,我们在这里就不再赘述了。Apache共通过inode +

mtime产生一串字符串作为ETag发送给客户端。它是消耗性能的,也存在安全风险
。同时,对于多服务器(web集群)而言不同服务器httpd守护进
程产生的ETag是不一致的。所以,如果你使用ETag的时候,认真的询问自己是否真的有必要使用ETag!~如果你跟我们一样,觉得暂时没有必要,则通
过以下配置关闭ETag(我们使用的是Apache)

FileETag none

最终,经过我们优化最终的快照如下图:



跟第一次的快照对比,优化的效果还是很明显地

1,请求数量,由最初的8个变成了现在的1个

2,发送包大小,由3400bytes缩小到现在的718bytes

3,响应包大小,由最初的146081bytes缩小至1025bytes

4,页面加载时间,由最初的10.296秒减小至现在的0.811秒

避免重定向

重定向虽然有的时候在跟踪流量,页面跳转等情况下随着业务需求难以避免,但是我们还是要尽量避免重定向的可能
,它是很伤页面性能的。最常见的重定向是
301和302。下面,我们访问了回复最多的一条贴子<<PHP session
浅析I>>。我们会发现多了很多条请求,还有重定向。这些请求发向gavatar.com主机,从avatar这个关键来看,我们可以确定该
请求是用于下载回复者头像图片的请求。所以,我们把Wordpress回复头像功能禁用了,之后又恢复了太平。




禁用wordpress回复头像功能后的一个快照




我们对比禁用头像功能后的快照,页面下载速度明显比没有禁用头像功能的页面下载快很多。请求数量,请求数据包总大小,响应包总大小,页面下载时间都明显下降。

Web前端优化CheckList

除了上述web前端优化准则,还有一些准则我们这里并不”适用”。必须这是一个blog,应用并不复杂。这些准则在各用web应用都是非常有帮助的。所以,我们这里整理了一份Web前端优化CheckList

1)图片地图,减少请求数量

2)CSS Sprites,它总是能够减少请求数量

3)内联图片,小图标可以使用内联图片,减少请求数量

4)合并外置js或css脚本文件,减少请求数据

5)Expires,缓存响应到用户本地,减少请求数量

6)Gzip压缩,压缩text类型的http响应数据包,减小网络数据传递量。

7)代理缓存

8)CSS样式脚本放在页面的顶部,尽早加载

9)Javascript脚本放在页面的底部,延迟加载

10)并行下载,将不同的组件请求通过CNAME使用不同的URL。

11)减少DNS查询,缓存DNS查询

12)精简Javascript脚本和CSS脚本

13)避免没有意义的重定向

14)避免Javascript脚本重复调用

15)ETag?

16)保持连接Keep-Alive

17)外置Javascript和CSS

18)Cookieless请求,尽量少使用Cookie,把数据存放在服务端

19)精简http请求数据包。Query_String不要太长和Cookie记录不要过多

20)延迟加载Javascript

受篇幅影响,我们将不在这里详细介绍,你可以通过阅读Google Page Speed Document和High Performance Web Sites。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息