提升网站性能 设置合理的cache时间(3)
四,我对HTTP协议做的一点创新(?maxage=6000000)
上面看到了url后面有 ?maxage=xx 这样的用法,这不是一个普通的参数,作用也不仅仅是看起来那么简单。他至少有以下几个好处:
1,可以控制HTTP header的的 max-age 值。
2, 让用户为每个资源灵活定制精确的cache时间长度。
3, 可以代表资源版本号。
首先谈论对后端的影响:
服务器实现那块,不用再load类似mod_expires,mod_headers 这样额外的module,也不用去加载那些规则去比较,它属于什么目录,或者什么文件类型,应该cache多少时间,这样的操作是需要开销的。
再说说对前端的影响:
比如同一个分时行情图片,我们的分时页中需要1分钟更新,而某些首页中3分钟更新好。不用js控制的话,那我cache应该设置多少呢? 有了maxage就能满足这种个性化定制需求。
另一种情况是,我们为了cache,把某个图片设置了一个永久cache,但是由于需求,我必须更新这个图片,那怎么让用户访问到这个更新了的图片呢? 从yahoo的资料和目前所有能找到的资料中都描述了同一种方法,更改文件名字,然后引用新的资源。 我觉得这方法太土, 改名后,老的还不能删除,可能还有地方在用,同一资源可能要存两份,再修改,又得改个名,存3份,不要不把inode当资源。 我就不那样做,只需要把maxage=6000000 修改成 maxage=6000001 ,问题就解决了。
maxage=6000000 所产生的威力 (内存块消耗减少了250倍 ,请求数减少了37倍) :
体育那边要上一个新功能,一开始动态获取那些数据,我觉得那样太浪费动态池资源,就让他们把xml文件到转移到我的js池上来,为了方便,他们把那个84k的flash文件也放在了一起,而且是每个用户必须访问的。 说实在的,我不欢迎这种大块头,因为它不可压缩,按正常来说,它应该代表一个3M的文件。我的服务器只这样设计的,如果一次发送不完的就暂存在内存里,每个内存块10k,如果不带参数默认maxage=120 。 我发现,由于这个文件,10w connections的时候,我消耗了10000个内存块。我自己写的申请连续内存的算法也是消耗cpu地, 一个84k的文件,发送一次后,剩余的64k就应该能装的下,于是我把最小内存块大小改为64K。 这样消耗10w conn的时候消耗1500个左右内存快,虽然内存消耗总量没怎么变小,但是它能更快的拿到64K的连续内存资源,cpu也节约下来了。接下来我让meijun把所应用的flash资源后面加上maxage=6000000 (大概=79天,浏览器端最长cache能达到着个就不错了), 10w connections的时候,只消耗了不到40个内存块,也就是说内存块消耗减少了250倍 ,请求数减少了37倍。 35w+ connections, 5.67w req/s的时候也就消耗100块左右,比线性增加要少很多。也就是这点发现让我有了做这个技术分享的冲动,其他都是顺便讲讲。
五.Yslow优化网站性能的14条军规点评
其中黑色部分,跟后端是紧密相连的,在我们的内容中都已经涉及到了,而且做了更深入的讨论。兰色部分,5,6,7是相关页面执行速度的,构建前端页面的人应该注意的。 11属于避免使用的方法。 红色部分我着重说一下:
gzip 我不推荐使用,因为有些早期IE支持的不好,它的表现为直接用IE访问没问题,用js嵌进去,就不能正常解压。这样的用户占比应该在2%左右。这个问题我跟踪了近一个月,差点放弃使用压缩。 后来发现我以前用deflate压缩的文件却能正常访问。 改用deflate问题解决。apache 1.x使用mod_gzip ,到了 2.x 改用cmod_deflate,不知道是否跟这个原因有关。 另外对于小文件压缩来说,deflate 可比 gzip 省不少字节。
减少 DNS 查询: 这里也是有个取舍的,一般浏览器最多只为一个域名创建两个连接通道。 如果我一个页面嵌了 image.xx.com 的很多图片,你就会发现,图片从上往下一张张显示出来这个过程。这造成了浏览器端的排队。 我们可以通过增加域名提高并发度,例如 image0.xx.com ,image1.xx.com ,image2.xx.com,image3.xx.com 这样并发度就提上去了,但是会造成很多cache失效,那很简单,假如我们对文件名相加,对4取mod,就能保证,某个图片只能通过某个域名进行访问。 不过,我也很反对一页面请求了数十个域名,很多域名下只有一到两个资源的做法,这样的时间开销是不划算的。
另外,我在这里再添一个第15条:错开资源请求时间,避免浏览器端排队。
随着ajax的广泛使用,动态刷新无处不在,体育直播里有个页面调用了我一个域名下的6个文件,3个js,3个xml。 刷新频率大致是两个10秒的,两个30秒的,两个一次性载入的。观察发现正常响应时间都在7ms,但是每过一会就会出现一次在100ms以上的,我就很奇怪,服务器负载很轻呢。meijun帮我把刷新时间错开,11秒的,9秒的,31秒的,这样响应在100ms以上的概率减少了好几倍,这就是所谓的细节决定成败吧。
1. 尽可能的减少 HTTP 的请求数 [content]
2. 使用 CDN(Content Delivery Network) [server]
3. 添加 Expires 头(或者 Cache-control ) [server]
4. Gzip 组件 [server]
5. 将 CSS 样式放在页面的上方 [css]
6. 将脚本移动到底部(包括内联的) [javascript]
7. 避免使用 CSS 中的 expression_r_r_r_rs [css]
8. 将 JavaScript 和 CSS 独立成外部文件 [javascript] [css]
9. 减少 DNS 查询 [content]
10. 压缩 JavaScript 和 CSS (包括内联的) [javascript] [css]
11. 避免重定向 [server]
12. 移除重复的脚本 [javascript]
13. 配置实体标签(ETags) [css]
14. 使 AJAX 缓存
六.上线了 !=Finished
奥运期间我按1500w~2000w connections在线,设计了一套备用系统,现在看来,如果用户真达到了这个数目我会很危险,因为有部分服务器引入了32bit的centos 5未经实际线上检验,而我当时简单的认为它应该和centos 4表现出一样的特性。所以现在未经过完全测试的lib库和新版本,我都很谨慎的使用。没在真实环境中检验过,不能轻易下结论。
很多项目组好象不停的忙,做新项目,上线后又继续下个新项目,然后时不时的转过头去修理以前的bug。如果一个项目上线后,用户量持续上升,就应该考虑优化了,一个人访问,和100w人访问,微小的修改对后端影响是不能比较的,不该请求的资源就让它cache在用户的硬盘上,用户访问块了,你也省资源。上线仅仅代表可以交差了而已,对于技术人员来说持续的对一个重要项目进行跟踪和优化是必要的。
七.提速度同时节约成本方法汇总
1,编写节约的HTTP服务器 (高负载下速度明显提升,节约5~10倍服务器)
对一些重要的服务器量身定做。或者选用比较高效的开源软件进行优化。
2,不同服务混合使用 (节约1~2倍服务器)
如果我们一台服务器只支持30w conn的话,那么剩余的75% cpu资源,95%的内存资源,和几乎所有的磁盘资源都可以部署动态池系统,我觉得DB对网卡中断的消耗还是有限的,我也不用新买网卡了。
3,对于纯数据部分启用新的域名(速度有提升,上行带宽节约1倍以上)
比如我们另外购买了sinajs.cn 来做数据服务,以避免cookie,节约带宽。 Cookie不但会浪费服务器端处理能力,而且它要上行数据,而通常情况上行比下行慢。
4, 使用长连接 (速度明显提升,节约带宽2倍以上,减少网络拥塞3~无数倍)
对于一次性请求多个资源,或在比较短的间隔内会有后续请求的应用,使用长连接能明显提升用户体验,减少网络拥塞,减少后端服务器建立新连接的开销。
5,数据和呈现分离,静态数据和动态数据分离 (速度明显提升,同时节约3倍带宽)
div+css 数据和呈现分离以后,据说文件大小能降到以前的1/3。
把页面中引用的js文件分离出来,把动态部分和静态部分也分离开来。
6,使用deflate压缩算法 (速度明显提升,节约3.33倍带宽)
一般来说压缩过的文件大小不到以前的30% 。
将上面分离出来的数据进行压缩(累计节约带宽10倍)。
7, 让用户尽可能多的Cache你的资源 (速度明显提升,节约3~50倍服务器资源和带宽资源)
将上面分离出来的css和不经常变动的js数据部分cache住合适的时间。(理想情况,累计节约带宽30~500倍) 。
以上改进可以让速度大幅度提升的同时,服务器资源节约 5~20 倍 ,减少网络拥塞3~无数倍, 上行带宽节约1倍以上,下行带宽节约30~500倍,甚至更多。