web前端优化

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 [email protected]

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。

你可能感兴趣的:(JavaScript,apache,Web,css,wordpress,etag)