无忧技术网 - RSS订阅 
无忧技术网

浅谈PHP程序开发中的缓存技术


作者:老王 - 发布:2010-4-22 17:35:38 - 来源:无忧技术网

为什么要使用缓存技术?理由很简单:提高效率。在程序开发中,获取信息的方式主要是查询数据库,除此以外,也可能是通过Web Services或者别的某种方法,无论哪种方法,在大量的并发访问面前,它们都可能成为效率的瓶颈,为了解决这些问题,人们提出了很多解决方案,其中一些是利用优化软件(如:APC,Eaccelerator,Zend Optimizer等等)来提高程序的运行效率,合理的运用这些软件,往往能使程序的运行效率得到数量级上的提升,但前提是你必须拥主机的控制权,以便能够安装这些软件,如果你使用的是虚拟主机的话,那么只能祈祷你的服务提供商已经预装了某个优化软件,否则就必须自己使用PHP来实现相应的缓存功能。如果这让你感到无所适从,相信下面的文字能给你一些启发。

很多PHP程序员都使用Adodb+Smarty这样的黄金搭档,那么就先看看如何使用它们的缓存功能。

首先看看adodb提供的数据缓存功能:

< ?php
include('adodb.inc.php'); 
# load code common to ADOdb 
$ADODB_CACHE_DIR '/usr/ADODB_cache'

$conn = &ADONewConnection('mysql');  
# create a connection 
$conn->PConnect('localhost','userid','','agora');
# connect to MySQL, agora db 
$sql 'select CustomerName, CustomerID from customers'

$rs $conn->CacheExecute(15,$sql
); 
? >

如上,每次查询数据的时候,会把相应的结果序列化后保存到文件中,以后同样的查询语句就可以不用直接查询数据库,而是从缓存文件中获得。

 

再来看看Smarty提供的页面缓存功能:

< ?php
require('Smarty.class.php'
);
$smarty = new Smarty
;

$smarty->caching = true
;

if(!
$smarty->is_cached('index.tpl'
)) {
    
// No cache available, do variable assignments here.
    
$contents = get_database_contents
();
    
$smarty->assign($contents
);
}

$smarty->display('index.tpl'
);
? >

如上,每次访问页面的时候,都会先检测相应的缓存是否存在,如果不存在,就连接数据库,得到数据,完成模板变量的赋值,显示页面,同时生成缓存文件,这样下次访问的时候缓存文件就发挥作用了,而不会再执行if块的数据查询语句了。当然,在实际使用中会有很多东西要考虑,比如,有效期的设置,缓存组的设置等等,具体可以查看Smarty手册中有关缓存(caching)的相关章节。

以上两个PHP流行组件缓存方式的侧重点是不同的,对于Adodb的缓存而言,它缓存的是数据,对于Smarty的缓存而言,它缓存的是页面。其他提供缓存功能的组件还有很多(如:PEAR::Cache_Lite等等),实际编程中使用哪个方案要具体情况具体分析,也可能会综合使用。

使用这些组件内置的缓存方案有一个很明显的好处是它们的实现对客户端而言都很透明。只要进行必要的设置(如:缓存时间,缓存目录等等)就可以了,而不用过多考虑实现缓存的细节问题,系统会根据设置自动管理缓存。但是其缺点也同样明显,因为每次请求仍然要用PHP解析一遍,效率和纯静态相比还是大打折扣,在大的PV面前还是不能满足要求,在这种情况下,仅仅做动态缓存就不够了,必须实现静态缓存。

这里所说的静态缓存是指直接生成展现给客户端的静态文件(如:/2006/07/21/123.htm)。这样做的好处很多,首先,因为已经生成了html文件,所以对应的页面请求只要apache解析就可以了,而不需要PHP插手,因此,效率提升会很明显,其次,这样会更符合搜索引擎友好的要求,增加站点被检索的概率,而且静态化还又一个好处就是即使你的数据库挂了,站点依然可以保证正常浏览,此外我们可以把这些静态化的文件利用rsync之类的软件同步到不同的web服务器上,再配合DNS轮循,达到负载平衡。但是静态缓存的缺点也是明显的,首先程序员不得不仔细考虑缓存的技术实现细节,而且如果出现了类似更换模板风格的需求变化,还不得不重新更新所有的静态页面(合理的使用CSS布局在某种程度上可以避免这个问题)。

抛开这些琐碎的观点,让我们来看看静态缓存的具体实现及可能出现的相关问题。

静态缓存无非就是把对视图渲染所得到的内容保存在一个.htm文件里,如果使用Smarty的话可以简单的调用其fetch方法来得到模板渲染的结果,更通用的方法是使用输出缓冲函数。

< ?php
//在最开始打开输出缓冲
ob_start
();

//若干输出
echo '模板渲染的输出内容'
;

//得到输出缓冲内容并清除输出缓冲内容
$content = & ob_get_clean
();

//生成静态文件
$fp fopen('example.htm''w'
);
fwrite($fp$content
);
fclose($fp
);
? >

这样看来,静态化似乎是很简单的,可惜实际上有很多复杂的情况要考虑,比较典型的情况是列表页的静态化,一般对于实时性要求不高的列表页,我们可以利用crontab定时触发(一般都选夜深人静的时候进行)相应程序来生成静态页面,但对于象论坛帖子列表页这样实时性要求很强的列表页,这样显然是不可能行的,它们除了实时性强的特点外,通常还都是倒序排列的,而且还会涉及一些“置顶”之类的帖子,如果按照普通的思路来静态化页面,那么每次发一个新帖子,就会导致所有的论坛帖子列表页都要重新静态化一下,要是页数很多的话,对系统而言这无疑是一个很大的负荷,而且很可能头一次静态化还没执行完,紧接着又要开始新一轮的静态化了,系统的效率就在这些无谓的操作中损失了。那么让我们看看如何解决这个问题,这里说一个还不是太成熟的解决思路:保持论坛帖子列表的第一页是“动态”的,以后的页都是“静态”的,假设每页显示N条帖子,当发表了新帖子的时候,并不重新生成帖子列表,这时候第一页的帖子数是N+1条,而第二页及以后保持不变,再有新帖的时候同样这么处理,于是第一页的帖子数会不断地增加:N+1条,N+2条,......直到2N条,这个时候,把N+1到2N的帖子静态化成第二页,一切开始重复上面的过程。当然了,细心的读者这时候可能会提问:新生成的第二页必然会导致页码的变化。确实如此,在生成第二页的同时,要对应的修改所有的帖子列表页的文件名,如/list/2.htm要改成/list/3.htm,以此类推。此方法和最开始介绍的方法相比,不用重新静态化已经存在的列表页的具体内容,而只需要修改文件名,无疑高效了很多,但即使这样还有一个问题,因为每个页面都包含“首页,上一页,下一页,尾页”的导航代码,所以页码的更改必然会影响到导航,对于这个问题,可以把和导航相关的代码提取到Javascript文件中,利用Javascript分析页面的URL来完成导航。

这还只是粗略的考虑添加帖子的情况而已,如果再考虑到删除帖子的情况,问题同样很多,,所以对于这样复杂的情况,如果没有考虑周详,最好别使用静态化缓存,比较而言,使用memcached等软件把论坛帖子列表页面的数据动态缓存到内存来提高效率的方法比较简便。

责任编辑:liqwei
打印本页】【关闭本页】【返回列表
·上一篇:php程序如何生成验证码图片
·下一篇:为什么PHP令人不爽(对于大型系统)
 文章评分
  • current rating
-5 -4 -3 -2 -1 0 +1 +2 +3 +4 +5
 相关文章
·[运维管理]国外百万级PHP网站架构分析 (2011-08-18)
·[PHP]优秀的PHP程序员至少应该了解PHP代码的优缺点 (2011-08-18)
·[PHP]PHP6将实现的8个特性和功能 (2011-08-17)
·[PHP]PHP容易被人忽略的10件事 (2011-08-08)
·[PHP]PHP 5.3/5.2 版本的选择 (2011-02-18)
 相关评论
 站点最新文章 更多>> 
·[经典影音]弱点
·[经典影音]萨利机长
·[经典影音]天空之眼
·[管理知识]康奈尔笔记法,提高100%学习效率
·[管理知识]刘强东:我管75000人靠这4张表格
·[管理知识]跟壳牌学HSE管理
·[运营策划]编辑工作内容整理
·[至理名言]奋斗与决定
·[瀚海拾遗]盲人打灯笼之各家论道
·[搞笑段子]中国男足
 站点浏览最多 更多>> 
·[协议规范]http断点续传原理:http头 Range、…
·[JS/CSS/HTML]HTML 空格的表示符号 nbsp / en…
·[NoSQL]Mongo数据库简介
·[协议规范]什么是SPF记录?如何设置、检测SP…
·[协议规范]图解 HTTPS 通信过程
·[PHP]精选国外免费PHP空间推荐
·[程序综合]常用IP地址查询接口
·[程序综合]什么是 DNS Prefetch ?
·[程序综合]获取客户端IP地址的三个HTTP请求…
·[Linux]/usr 目录的由来