在过去,有些开发人员认为ColdFusion“太慢了”。不论这在过去是真还是假,现在这当然不是真的。随着ColdFusion MX运行在Java之上,CF在性能上有了显著的提高。但是,除了对CFMX本身及其调试Java代码方式的调整,还有一些因素会拖累服务的速度。在本文里,我将告诉你一些能够更进一步提高CF应用程序速度的方法。
服务器的设置
首先,保持CFMX本身总是
更新到最新的版本,并安装有最新的
补丁程序。
CFMX 6.1带有并运行在
Sun 1.4.2版的Java虚拟机(Java Virtual Machine,JVM)之上。尽管这是对CFMX 6.0版自带的旧版Java虚拟机相当好的升级,但是这并不意味着你可以忘掉服务器也需要这一重要方面的升级。你应该紧盯着Sun的Java Web网站,当有新版本(比如1.5.0版)发布的时候,你应该认真地考虑是否应该更新CFMX所使用的虚拟机。除了加入了新的特性,Sun还提高了每个新版虚拟机的性能。你可以在ColdFusion管理员的“Java和Java虚拟机”这一部分里设置虚拟机及其可以使用的最大和最小内存量。
一旦你让最新版本的CFMX和Java运行起来了,就有一些服务器设置可以被调节以提高性能。在ColdFusion管理员的“设置(Settings)”页面上有一个“最大并发请求(Maximum Simultaneous Requests)”的设置项。这个值的设定可以说是一门艺术而不是一项技术,因为这个值的大小在很大程度上取决于服务器和应用程序的具体情况。不论任何,这是一项重要的设置。如果这个值太低,你就会碰到请求的排队,结果导致运行减慢。如果这个值太高,CPU就会因同时处理过多的线程而造成负担过重。我总结出来的一个基本原则是,把这个值设置为服务器处理器数量的3到4倍。但是再强调一遍,这只是一个估计值。获得最适合于你的服务器的数值的真正方法是在不同的设置下运行一些负载测试。
在CF管理员的“缓冲(Caching)”页面上,你会看到多个影响性能的选项。每个选项的目的都在页面的右侧有相当清楚的解释,但是我会专门地把它们过一遍。你可能希望把“最大缓冲模板(Maximum Cached Templates)”的数量设置得高一点,以等于或者高于正在服务器上运行的模板的数量。在一个正在运行且其中的文件不会进行较大改变的服务器上,你可能想要查看“受信缓冲(Trusted Cache)”。通过这种方式,CF会假设它放在内存里的模板的版本是最新的,因此它就不会再检查磁盘上的版本了。你还希望检查“保存类文件(Save Class Files)”。CF会把从CFML模板生成的编译类文件保存到到硬盘上。然后CF就对每个请求使用保存类文件而不是重新编译。
最后一种的提高性能的方式来自调试的禁用。我不是说只停止调试所有的IP地址;我真正指的是完全关闭调试。在运行大量使用ColdFusion组件的应用程序时,例如一个
Mach-II应用程序,调试会极大地影响该应用程序的处理速度。就我的经验而言,关闭调试可以把一个相当简单的Mach-II应用程序的性能提高5倍!
数据库交互
CF应用程序(或者任何用于它的Web应用程序)的最著名的一个瓶颈和数据库有关。事实上,所有的Web应用程序都存在着和数据库的某种交互操作。这一点可以由人们认为“数据库会处理它”的想法得到证实。从某种程度上讲,这是真的,因为大多数企业级的关系型数据库管理系统(RDBMS)的最新版本里都有相当智能化的查询优化器。但是,仍然有一些东西是数据库无法自行完成的。
关于数据库和SQL查询的优化,人们可以写一整本书(事实上很多人已经写了)。我写这篇文章的目的是,根据我的经验,能够指出一些地方,这些地方的一些简单变化就能够给应用程序的性能带来巨大的影响。
第一个是正确的索引。当你查询数据库表格,而你的WHERE或者JOIN子句里没有对字段的索引时,数据库就别无选择,只有扫描整个表格来查找匹配的内容。如果你的表格里有几百万个数据行,这就成了一件非常糟糕的事情。对字段的正确索引能够极大地提高SELECT语句的性能。
主关键字字段应该已经被数据库索引了,但是要注意一下WHERE或者JOIN子句里那些没有被索引的其他字段,而且如果它们经常被使用,就要考虑对其进行索引。但是,不要对每个表格里的所有数据列都进行索引。就和计算机程序世界里的一切一样,索引也有其不足之处。首先,它们会占用磁盘空间。其次,尽管它们会加速SELECT语句,但是它们会减慢INSERT和UPDATE语句的速度,因为反映新的数据就必须重建索引。
让速度大幅提高的另一个因素来自于绑定变量的使用。在CF里,这是通过在你的SQL语句里使用
<cfqueryparam>标记来完成的。在这样做不仅仅要比直接在你的SQL里直接使用CF变量更加安全,而且这样速度要快得多。这是因为使用捆绑变量会告诉数据库这样的内容:“把这个SQL语句放在内存里,而且事先知道唯一会发生改变的是捆绑变量——其他所有的东西都不会发生变化。”此外,你要在
<cfqueryparam>里指定变量类型,这样数据库就知道要一直处理相同的数据类型了。
最后,CF为把数据库查询完全缓冲到CF服务器的内存里提供一个很好的选择。这会完全跳过对数据库的调用,所以带来了性能的极大提高。就和CF里大多数的东西一样,这非常容易实现。只用简单地把
cachedwithin属性添加到你的
<cfquery>标记里就行了。例如
Listing A里的例子会把查询放在内存里缓冲一个小时。
结果集会被放在CF服务器内存里缓冲,未来对同一个(完全相同)SQL语句的请求会使用被缓冲的结果集,直到缓冲超时。这里的一个不足之处是,你不能在
cachedwithin缓冲的查询里使用绑定变量。
如果感觉自己具有冒险精神,你可以考虑使用存储过程、触发器,以及用户定义的函数,只要你的关系型数据库管理系统支持它们的话。想学习和实现它们可能是相当复杂的,但是它们能够带来编译性能和安全上的一些提高。
CFML有一个很好用的标记(<cfcache>),它允许你缓冲整个页面。你可以设置这个标记,让其在客户端、服务器上,或者同时在两端进行缓冲。通过在“timespan(时间间隔)”属性里指定一个超时的值,你可以告诉CF页面需要被缓冲多长时间。你还可以指定一个目录,让CF写入缓冲页面后供后面的读取。在缺省状态下,这个目录是你CFMX根目录下的cache。
尽管<cfcache>可以用在某些情况下,但是它有一个很大的缺点。首先,由于它把缓冲的页面写到磁盘上,所以随着管理的缓冲页面越来越多,性能也会下降。而且使用<cfcache>很难只缓冲页面的特定部分。由于这些问题的存在,Brandon Purcell创造了<cf_accelerate>这个自定义标记。
这个标记真的很让人吃惊。你可以用它把整个页面上的全部内容或者部分内容包起来,并用它来缓冲其中的内容。很好的一件事情是,它会把数据缓冲到服务器内存里(使用应用程序的范围)而不是硬盘上。其结果让人印象深刻。我的一些简单测试表明,如果对缓冲和非缓冲文件进行10,000次循环迭代,那么使用<cf_accelerate>要快4倍。Brandon进行过强度更大的测试,他让CFMX在自己2-GHz的笔记本计算机实现了每秒310页的发送。关于<
cf_accelerate>标记用法的细节已经可以看到了。
速度
CF正在变得越来越快,Macromedia已经在继续提高其性能上做得非产出色了。但是你总是能够在开发和服务器管理上做点什么,给你的应用程序带来额外的性能加速。我希望你也能够找到使用上述提示和技巧的办法来加速自己CF应用程序的速度。
责任编辑:
李宁
欢迎评论或投稿