PHP开发大型Web应用浅析
关于PHP的执行效率,网上的专题文章很多,多是PHP、Java几个阵营的争论;应用的方面不同,执行环境不同,效率的差别会差得比较大。这里所说的“ 大型”应用不是说像Google、eBay、Yahoo这类大型网站的具体实施,只是希望大家的系统可以运行得更快更流畅,可以承载更多的用户在线,希望可以给PHP的初学者一点帮助。
这里所说的“大型”应用不是说像Google、eBay、Yahoo这类大型网站的具体实施,我也没有意图劝说读者放弃自己的概念和信仰,只是希望大家的系统可以运行得更快更流畅,可以承载更多的用户在线,希望可以给PHP的初学者一点帮助。
关于PHP的执行效率,网上的专题文章很多,多以PHP、Java几个阵营的争论开始,以一个不确定的期待结束,很少看见一个明确的结论。确实,程序的执行效率是很难从比较中得出的。应用的方面不同,执行环境不同,效率的差别会差得比较大。而且效率也是需要权衡的,大家都知道汇编语言很底层,可以写出非常高效的程序,但是我还很少,应该说是几乎没看过有人用汇编做Web开发,而且有能力用汇编写出高效程序的人似乎都是值得大家仰视的,哈哈~我们没有必要去讨论PHP和汇编到底差多少,只要知道自己的PHP和别人的PHP差多少就可以了。
首先,先要明确这篇文章的前提:必须有一台或更多的可以被自己操纵的服务器,而不是虚拟主机空间。毕竟可以在虚拟主机上运行的通用系统已经有了很多经典的作品和成熟的框架,效率挖掘已经被前辈们做得非常出色了,它们的很多理念也被现在很多PHP用户继承和发展,越来越多的所谓“框架”也像满天繁星一样,我也不想再去写那个,因为第一我自己的水平也不怎么样,写不出什么新鲜玩意来,写出来也招人笑,第二是写这个的文章太多了,说法也太多了,混乱是造成很多富有激情的未来天才程序员夭折的最大元凶。
在独立服务器上执行的程序和在虚拟主机上可以运行的程序在效率优化方面有着很大差别。您当然可以把一套discuz不加修改地安装在一台甚至一堆独立服务器上,不过,它真的得到最大的性能优化吗,您真的对得起这一堆服务器吗?
独立服务器指的是,使用者对这台机器有完全的控制权,包括安装、删除软件,配置系统参数甚至修改源代码。基于这样一个开放的硬件平台,性能也不仅仅是体现在速度上,还包括安全性、稳定性等。和虚拟主机不同,用户必须自己配置Web服务器参数,安装和配置PHP、数据库,以及安装各种乱七八糟的东西(我喜欢这么说),当然还要对它们负责。
首先提出几个名词:执行时间、模板、数据库封装、Cache、Buffer、Hash、守护进程、crontab。
执行时间,谁都知道,就是一个程序从执行开始到执行结束所用的时间。因为Web是瞬时的、无状态的,所以执行时间是Web程序执行效率的一个指标,它并不适合衡量C/S程序或者后台守护的程序,因为它们很多都是持续运行的。页面执行时间的一个典型例子就是Discuz论坛页面最下方的时间显式,通常 Discuz都是几毫秒到几十毫秒,和所用的平台、数据量和当前系统压力有关。
模板大家再熟悉不过,虽然有很多人只是在用,但是不知道为什么在用。模板在传统上来说是划分逻辑层的一种途径,在MVC上结构里,它把表示层和下层分离,在实际使用中,它方便程序员和界面设计人员分工合作。然而,现在很多场合中,由于模板的不当使用,它非但没有起到促进程序员和界面设计人员分工合作,反倒成为程序员和美工互相仇视的罪魁(我好像在以前的帖子里这样说过),很多人在抱怨他们不得不花很多时间在整理模板上。
数据库封装似乎和Java的关系更大,它对多种数据库系统提供一个统一调用接口,通常是一些封装好的类,这些类有时也完成一些比如SQL检查、过滤等工作。PHPLIB里的DB封装、PEAR DB、Adodb等都很有名,用的人也很多。
Cache和Buffer看起来好像是一种东西,Cache叫做缓存而Buffer叫做缓冲。在硬件概念中,Cache的用途是连接两种速度不同的设备,比如寄存器和内存、CPU和PCI-Bus、IDE总线和硬盘。Buffer的原意是类似弹簧的一种缓冲器,用来减轻或吸收冲击的震动的东西。 Buffer是一种数据预存取的方式,它用于临时存储数据并以与接收速度不同的速度传输。Buffer的更新方式可以是按时间间隔自动刷新,而Cache 则更讲究“命中率”,将当前时间段使用频繁的少量数据放到高速设备中方便读写。在程序开发中,固然没有什么高速、低速设备,不过数据源是可以有不同读写效率的。对于少量数据,文本文件的读写通常就要比数据库存取效率好,而同样是文本文件读写,在tmpfs上的效率就要比直接的磁盘IO效率好。Buffer 更多地体现在进程通信和队列上,很多时候并不是因为接收方没有能力更快地读取,而是没有必要更快地读取。
守护进程是一种在后台连续执行的程序,它通常是起到监视、控制流程、对外提供服务等作用。比如Apache本身就可以被理解成一个守护进程,虽然它实际上是由很多个经常更新的进程组成(主进程是固定的)。
Crontab是UNIX/Linux的定时程序,有点像Windows的“计划任务”,它设定在多少个时间间隔后或者是某一个时间点执行特定的程序。它通常用来完成自动更新、清除临时数据等一段时间自动执行一次的操作。
另外一个比较特别的概念(说它特别是相对于习惯了通用系统开发的人来说),是当我们拥有了一台独立的服务器之后,完全没必要把自己局限在PHP所能提供的功能范围内,当我们不知不觉地成为系统的主人后,要努力发现到这一点,我们有很多东西可以用的。PHP不是万能的(这简直是一定的),对于它的功能上的不足,完全可以用Perl来弥补,Perl做为一种通用语言,可以提供更多的功能选择,砂砾一样密的模块给这个随意得有些变态的语言提供了无穷的能量。对于PHP性能上的不足,完全可以用C来补充。PHP的根本就是由C继承来,PHP本身也是由C开发,用C来做PHP的扩展是完全合理的。
Linux本身就是由C和Perl在支撑(我这样说完全不是为了夸大Perl的地位,大家可以去看看一个标准的Linux中有多少Perl脚本,离开Perl之后这个系统是不是觉得像个残疾人)。PHP从C中继承了大部分的语法,从Perl中学习了大部分Web特性、函数和那个貌似与开源很矛盾的 “$”符号(PHP早期就是一个Perl脚本)。
下面来分析我在使用的一些代码(注:Linux独立服务器适用。我好像已经放弃对Windows和虚拟主机做大型开发很长时间了)。里面使用了一些也许很熟悉也许很陌生也许很变态的方法。我的系统是RedHat AS3,没有什么特别的,PHP版本是4.4.0,MySQL是4.1。我从来没有刻意地去写一些必须用到PHP5的新特性的代码,除非真的必须用到。
我的Web根目录在/www下,Apache、PHP都是默认安装在/usr/local/下,MySQL是下载的编译好的二进制版本,我也一样把它丢在那里。因为只是用于测试,我不想它看起来很乱,至于在实际项目中,尤其是多台服务器的情况下,需要好好地部署一下你的系统。
为了使系统的结构清晰一些,我把需要使用的文件都放在了二级目录下面。
下面是通用头文件/includes/kernel/common.inc.php的一些片断:
﹤?phpif (!defined('IN_BSG')) {exit;}?﹥
上面的代码保证它只能被合法的程序所调用,而不会被其它的文件include。如果正在执行的程序没有定义一个'IN_BSG'常量,它在include这个common.inc.php之后程序会终止。
﹤?phplist($usec, $sec) = explode(' ', microtime());$page_time_start = $usec + $sec;?﹥
这两行大家可能都会比较熟悉,这是计算程序的开始执行时间的。在程序结束之前,还会再计算一下这个,为的是得出程序执行所耗费的时间。如果你不在意这些,可以放心地把它注释掉。