欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

PHP沉思录-第六篇-Drupal的性能问题-左轻侯-《程序员》2008年11月号

程序员文章站 2024-01-23 08:57:22
...
创建时间:2008-11-09 01:12:51 最后修改时间:2008-11-09 01:12:51

本文发表在《程序员》杂志2008年第11期

PHP沉思录之六:Drupal的性能问题
左轻侯

Drupal是一个基于PHP的开源CMS系统,也是我认为技术上实现得最好的一个PHP应用。Drupal的架构非常优秀,通过微内核+plugin的方式,实现了极佳的扩展性,从而使Drupal远远超出一般的CMS这一范畴。从这个意义上来说,把Drupal称为Web OS似乎更加合适一些。关于Drupal,有太多的话可以说,也许我会在以后的时间里写一篇文章对它进行专门的讨论。但是在本文中,我想讨论的,是Drupal社区中的每一个人都会面对,但不是每一个人都对其有清晰认识的问题,即Drupal的性能问题。
因为客户需求,我曾经对Drupal做过比较全面的测试。当时的环境是双服务器(DB server+Web Server),硬件配置都是单CPU+4G。数据库里面有几千条Node记录。用JMeter对各种情况下(开/关各种cache模块,logged user/anonymous user)不同页面的读取和写入操作都进行过测试。
测试的结果可能和很多人印象中不一样。两个主要的结果如下:

1. Logged user和anonymous user的性能差距非常大。同一个页面,logged user的RPS(Requests per second)一般不超过20,而启用了cache的anonymous user的RPS在100多,当使用了file-based cache以后,甚至能超过300。
2. 数据库压力相对较小。由于Drupal把大量可配置的内容都放在数据库中,因此往往容易产生这样一种印象,即Drupal对数据库要求应该是很高的。但事实上,无论是cache还是非cache模式,DB server的压力都相当小(CPU在10%以下),而Web Server的CPU在80%以上。跟踪所有的db query的执行时间后,也证明了这一点(全部db query的执行时间只占页面生成时间的一小部分)。

经过反复的测试和思考,我得出了一些结论。很明显,Drupal在大量logged user并发情况下的瓶颈,在于执行Drupal代码的CPU时间,而不是在于数据库或者其他地方。之所以出现这样的情况,和PHP本身的执行机制和Drupal的实现方式有关。Drupal在生成一个非cached的页面时,不管这个页面多么简单,都要执行一个完整的bootstrap过程,即使只启用了最少的模块,这个过程也要调用几十个PHP文件,执行成千上万行PHP代码。而PHP的机制又决定了没有任何PHP代码或者对象能够驻留内存,每次响应请求都必须执行完整的初始化工作。而anonymous user之所以快,是因为Drupal在执行cached page的时候,不会执行完整的bootstrap过程,它先检查是否cached page,是的话就读取缓存,然后结束工作。这样当然就快了。
以这个结论为前提,可以解释一些事情:

1. 为什么Drupal的性能在各种环境下相差并不多。无论是双服务器,单服务器,甚至内存非常小的虚拟机,logged user的RPS值往往总是在10~20之间。数据库里面有几百条,或者几十万条记录,影响也不大。因为瓶颈并不在于DB或者内存,而是在于执行代码的过程。
2. 为什么使用APC/XCache这样的代码优化程序,能够得到极大的性能提升。在我自己的虚拟机环境上,RPS从3~4提升到了12。因为它提升的是PHP代码的执行时间。

从这个结论出发,列出一些对优化Drupal的logged user性能有明显作用和没有明显作用的措施:

没有明显作用的:

1. 加内存。在并发数只有10+的时候,即使每个请求占20M内存,也只有200M+内存而已。
2. DB server和Web server分开,或者增强DB server的配置。一台中等性能的mysql服务器,应付200~300的并发是很轻松的事情,在并发数只有10+的时候,db server实际上是很空闲的。
3. 基础软件的优化,例如从Windows转移到Linux,从apache转移到Lighttpd,从MySQL迁移到其他数据库,除了从Windows转移到 Linux会有比较明显的提升以外(因为PHP在Linux上的效率比在Windows上要好),其它的措施可能会快一些,但不会有大幅度的提高,因为瓶颈不在那里。

有明显作用的:

1. 使用APC/XCache这样的代码优化程序,速度会有几倍的提升。估计大家都已经这样做过了。
2. 增加web server的CPU数量。双核的肯定比单核的快,4个CPU肯定比2个CPU快得多。
3. 使用多web server+单db server的配置,把代码执行的压力分散到不同的web server上。上文说到,单台db server可以轻松应付200+的并发,这意味着理论上可以支持10台以上的web server。
4. 使用Quercus这样的引擎,把PHP代码编译成Java,再在Java VM中运行,理论上会有很大的提高。原因是,第一,Java的运行效率比PHP高,第二,Java代码是可以cache的,不需要每次都重新加载。这里有个测试结果:http://www.workhabit.org/resin-backed-php-drives-4x-performance-improvements-drupal 。Drupal在Quercus下有4倍的性能提高,但是这个数字跟Drupal在打开APC/eAccelerator下的提升差不多,所以可能没有太大的实用价值。

另外一种思路是代码本身的优化。
使用cache API基本上是没有意义的,因为对于logger user,Drupal不会调用cache API。Drupal.org上有人提出,即使是logged user,有很多页面也是不用定制化的,这意味着可以cache它们。但是Drupal没有提供这样一种机制。只要是logged user,Drupal就会执行完整的bootstrap过程,即使只打印出一个hello world,因此实际上你没有办法在logged user状态下cache单个页面。
到目前最新版本的Drupal(Drupal 6.4)为止,对于logger user,Drupal只提供了一种cache功能,就是可以将部分block设置为可cache的。在block占用大量服务器时间的情况下,block cache能够有效地提高效率。但是,由于block cache对于bootstrap过程并无影响,因此当瓶颈在于bootstrap本身时,Block cache是无能为力的。
在Drupal.org的社区,关于logger user的cache问题,一直处于热烈的讨论之中。基本的结论是,由于Drupal的架构就是这样,目前没有很好的解决方案,只能期待Drupal在以后的版本中进行改进了。
我研究了一下Drupal的bootstrap过程,发现也许这样是可行的:实现hook_boot函数,这是bootstrap中执行最靠前的一个函数,它被调用时,bootstrap的大部分过程还没有执行。在hook_boot中,检查当前页面是否需要cache,如果是,直接读 cache生成页面,然后调用exit()强行结束。这在理论上是可行的,但太过hack了一点。
Drupal的情况是这样,那么其他的PHP框架,尤其是半官方的Zend Framework,性能如何呢?通过搜索,我在网上找到了一份PHP framework comparison benchmarks,网址见:http://www.avnetlabs.com/php/php-framework-comparison-benchmarks。根据这份报告的数据,Zend Framework的性能只有原生PHP的10%,如果没有用APC,连3%都不到。当然,这份报告的数据不一定详尽,Zend Framework在不同环境下的表现应该也会有出入。但是,Zend Framework的性能大幅度落后于Baseline PHP,应该是确凿无疑的。
为什么PHP主流框架的性能都存在着这样的问题呢?其实这也不难理解。回顾PHP沉思录系列第一篇中对于PHP工作模型的讨论,由于PHP没有驻留内存的进程,所以每一个request发生时,都必须初始化所有的对象,这导致大量的时间被耗费在进程代码的执行过程中。当PHP程序仅仅是简单的脚本时,这无关紧要,但是在结构复杂的架构中,由于每次处理request都要重复调用成千上万行代码,这一问题就变得非常突出了。而且,除非PHP以后的版本对这一机制进行改进,否则这个问题无法得到彻底的解决。
那么,这是否意味着,PHP只能适用于小型的网站,而无法在高并发量的大型网站施展拳脚呢?当然不是这样。事实上,在Yahoo和其他许多知名的巨型网站上,都大量地使用了PHP。原因在于,PHP仅仅被用作一个内容生成器,生成的内容会被转化为静态文本,绝大多数用户浏览的都是被cache的静态文本。这就和PHP程序的性能毫无关系了。但是,当用户并不是仅仅进行浏览,而是需要频繁地和网站进行互动时,PHP的性能不但无法比拟C和Java,甚至无法与同为脚本语言的Python和Ruby相比。也就是说,PHP更适合于新闻门户这样的内容发布站点,而不是web 2.0应用的首选。
在本系列文章告一段落的时候,我们看到的是PHP的局限性。热爱PHP的人们可能会对此觉得沮丧。但是,这并无损于PHP作为一门优秀语言的声誉。尺有所短,寸有所长,对于我们熟悉和喜爱的工具,我们更应该了解它们的局限,这也有利于我们更有效地使用它们。