« 让你的网站快100倍! (1) | Main | 余晟与《精通正则表达式》 »

让你的网站快100倍! (2) web程序的流程和层次

作者:virushuo 发表于 2007-07-16 04:07 最后更新于 2007-07-16 12:07
版权声明:按照by-nc-sa的cc协议可转载,拒绝采用“独家” 授权媒介(含网站和平面媒体)转载、引用、链接,除非获得本人许可。转载时请务必以超链接形式标明文章原始出处和作者信息及本声明。


我面试程序员的时候,最爱问的一个问题是:“请描述一下一个php(或.net/jsp...)页面被用户访问后,服务器都做了什么。”

这个问题看似简单,但是很多熟手都说不清。这也就说明了很多程序员并不真正理解web程序是如何工作的。不懂这个,就分不出层次,自然也就无从下手优化。这次我们先要把这个问题说明白了。

静态内容当然是这样。


有程序的就这样



有数据库的就这样



多个数据库作了复制或是集群或是负载均衡的就这样。



多个web服务器作了负载均衡就是这样


类似的东西还有很多。不过本质是一样的。都是用户请求到webserver,经过相应的处理模块(静态直接返回,cgi运行程序,动态脚本运行,虚拟机执行字节码生成html代码),将结果返回,这个过程中如果需要数据库,程序会连接数据库处理,取回结果。这个简单的过程就是web程序的本质。

无论多么复杂的结构,都是这些过程的组合。通常顺序也不会发生变化。知道了这个,我们回头看后面几个架构,就会发现他们做的事情都一样,就是把负载分开。当然这里分散负载的方式有很多,但原理无非就是2种,一种是分散开的各节点内容一样,所谓集群或是分布。这种做法好处是可以有通用产品。因为模式是统一的,就是复制出来多个一样的节点而已。另外一种是拆分服务,把不同的服务拆开到不同的机器上。这样做的好处是效率提升更大,每个部分都可以再进行单独优化,比如把负载最重的部分复制多个节点出来分散压力等等。后面我们讲到架构设计的时候再细致讨论这些问题。这里只做常识介绍。

负载问题的解决,常用的也是两种办法,一是开源,二是节流(其实所有问题解决都是这两种办法,企业管理也好,个人财务也好)。放到我们这个特定问题中,所谓开源,就是提高单个部分运行效率,让该部分能负担更多的工作。比如优化一下程序,优化一下数据库,都属于此类。所谓节流,则指降低对高资源消耗部分的使用次数。通常采用缓存的方式来处理。

我们沿着一个web程序的运行过程来看看具体的东西。这时候,我们先忘掉所有的负载平衡,集群之类的东西,集中精力来解决一个最简单的应用过程中的性能问题。

整个层次用图表示就是这样的:

蓝色是必备的层次,绿色是后期可加入的缓存,黄色是可以进行优化的部分,黄色的比例是一般情况下优化能带来的效果比例。看起来很简单?但实际做起来也没那么容易。

1 用户访问:我们当然可以通过降低用户重复请求同样的内容的方法来提高用户浏览速度和降低压力。
两种办法。一种是利用浏览器缓存,正确的设置http header中相关设置,让浏览器不重复请求没变化的内容。一般来说图片倒是可以这样做。页面也可以作一些,不过考虑到pv就是广告费的问题,还是让用户多多直接访问页面吧:D
另外一种办法是利用js,将部分数据存放在js脚本里面(js会被浏览器缓存),或是存放在cookie里面,用js取回。由此降低用户访问次数。

虽然有一些效果,但这些办法解决不了太实际的问题。所以不放在最优先考虑位置。

2 http server
用户的请求到达了web server,在这个层面,可以去硬盘读取静态文件返回给用户,也可能交给cgi程序继续处理。我们注意到,无论哪种处理方式,返回给用户的都是一个已经完成的html页面(或文件)。换句话说,就算是动态脚本,也是把处理结果生成html文件返回用户。如果我们能不重复这个生成的过程,那么对后端所有模块的压力都降低了。这个办法就是反向代理缓存。在http server之前使用。

3 cgi/vm
应用程序请求到达了cgi程序。那么最直接的考虑就是提高程序运行效率。不过,程序运行效率的提升多在几个毫秒的级别。除非程序非常糟糕,否则提升余地不大。而我们通常所感觉到的“程序响应慢”的原因,其实往往是在数据库上。

当然,这个层面会有一些特定的解决方案,比如zend对php的那些加速方案。(其本质仍然是不同层面的缓存)

4 database

终于到达了数据库这层。脚本和cgi程序访问数据库,获得数据才能生成html页面返回。这层的负担很重。

数据库优化是有效的。设计的好的数据库结构,搭配正确的sql语句,可以比最糟糕的设计提高数百甚至上千毫秒的时间。访问量大的时候,这个累计效应非常明显。

数据库设计往往决定了性能。鉴于目前关系型数据库的普及,很多程序员就把数据库当作了唯一的存储解决方案,任何东西都存放在数据库里。这当然是不对的,存储要结合应用特点,数据库不是万能的,很多操作在数据库中耗费资源巨大而性能非常低。例如全文like的搜索就非常消耗资源,远不如采用倒排索引的查询方式。

除此之外,数据库层面也可以进行缓存,例如memcached,或是在程序中缓存部分数据等。

5 高级优化

这些做起来就有些难度了。当所有性能都压榨完,我们只能回到web server和cgi程序本身。所以大型网站往往使用自己开发的web server(自行定制apache等),采用裁剪过的php库。

在我们还没有解决完其他部分之前,暂且不考虑这个。


顺着这个流程看,最有效,最值得做得事情显然是2和4,这些都是对系统架构改变不大,但是效果明显的方案。因此,下一章我们就从反向代理的应用说起。


ps: 另请转载此文的,请连图转走,或是留下本文链接。以免影响别人阅读。谢谢。我不在乎这点流量,所以转也就转了,但是不能因为少了图让别人看不懂。


tinyfool对此文亦有贡献

blog comments powered by Disqus
CC License. Some rights reserved.
署名·非商业用途·保持一致
本站之所有未作特别说明的内容均使用 创作共用协议.
POWERED_BY_MT_3.2