[字号:  ]

以Discuz!为例,分析PHP中的缓存技术

发布时间:2007-1-31 22:36   作者: 僭燮水   信息来源: PHPChina 开源社区门户
以Discuz!为例,分析PHP中的缓存技术关于PHP的缓存技术我个人的定义是可以分成3个类别
  • 1.缓存模块
    这这个是在服务器上做的缓存设置,比如Zend公司的Cache产品等,主要原理是通过对PHP代码文件的一次编译保存在内存中,通过减少I/O的操作来加快访问速度,不在本文讨论范围之列
  • 2.HTML方式
    或许你说PHP生成HTML的方式不在本文讨论的范围之列,但是我个人人为这种方式仍然是一种Cache方式,如现在流行的生成HTML的程序也有不少,比如国内的一些CMS,这个也不在本文讨论的范围之列,一笔带过.
  • 3.生成Cache文件
    这个就是对一些常用的而且又不是经常变动的量,保存在文本中,通过减少mysql的查询量来加快程序执行,详细的内容我们随后介绍
  • 4.php缓存机制
    举个例子说,smarty模版里面的缓存机制,比如目前Discuz!论坛用的缓存机制,后面具体说
我是把目前php的Cache分成了这四种机制,第一种方式,需要加载模块,可能是收费的比如ZEND公司的,可能是免费的,不过多讨论;第二种方式,比如在成熟的大的站点上用比较合适;第三种方式和第四种四目前PHP业内程序中比较流行的方式
以Discuz!论坛软件5.0版本(或许你说了为什么以Discuz!为例,而不以PhpWind或者其实CMS为例,主要是因为Discuz!和我要说的后面两种缓存机制结合的比较好,而其他软件产品都或多或少的不太合适本文的要求)为例,在第三种机制中,Discuz!将基本设置和常用变量保存在forumdata/cache文件夹下面的一个文件中,比如cache_settings.php就是论坛设置的中的数据保存在一个数组总并存在这个文件中,在需要这些变量的时候就通过include这个文件来使用这些变量;在第四种机制中,Discuz!是把templates/default中的模版文件,预编译,也就是在请求访问index.php文件的时候,程序先在forumdata/templates中是否已经生成预编译的文件,如果存在则包含,如果没有则在模版文件夹中寻找模版然后生成,再包含,这么一个处理流程
在这种处理机制下,在小负载小站点的情况下,显然会有不少浪费,但是在中大站点或者说大型超大型站点的具体实施中,表现优异,但是显然做论坛的貌似都是负载比较大,国内水论坛一堆哇
再过来看Phpwind论坛,做为国内PHP论坛唯一能在Discuz!的压力下值得一提的一个论坛系统,显然在缓存机制上的处理不是很好,PW以前貌似也是做文本论坛起家的,同样的文本对于I/O的压力是很大的,尤其是在大中型站点的负载均衡上
写到这里突然不想写了,本来是想谢谢插件开发中的对于缓存和模版的应用,然后突然想到写一些我个人对于当前php缓存机制的一些理解,写到这里,写了2遍,狗日的服务器,娘的MYSQL老是丢失超时,你娘,服务器配的有点水平和好,靠,不写了


Submitted by kimi On 2007年01月31日21时14分 Posted in PHP技术 永久地址 评论:0



写在http://www.ccvita.com/index.php/45.html
转过来 ,分享下 大家讨论下

最新回复

ok7758521ok at 2007-2-01 15:31:34
:lol 不错呀 。,。收藏
phpe at 2008-9-22 17:20:07

QUOTE:

原帖由 僭燮水 于 2007-1-31 22:36 发表
Discuz!是把templates/default中的模版文件,预编译,也就是在请求访问index.php文件的时候,程序先在forumdata/templates中是否已经生成预编译的文件,如果存在则包含,如果没有则在模版文件夹中寻找模版然后生成,再包含,这么一个处理流程
...
如果预编译的文件已存在,但是数据库里面的内容有改动,这个时候怎么办?
是不是检查一下有没有更新?如果有就重新预编译!如果没有就直接包含?
我就是不明白这一点,每次访问还去数据库里读一下,然后拿出来对比,这样还不如不比了,直接读数据库出来呢?

[ 本帖最后由 phpe 于 2008-9-22 17:24 编辑 ]
xinzf at 2008-9-22 18:11:14

QUOTE:

原帖由 phpe 于 2008-9-22 17:20 发表

如果预编译的文件已存在,但是数据库里面的内容有改动,这个时候怎么办?
是不是检查一下有没有更新?如果有就重新预编译!如果没有就直接包含?
我就是不明白这一点,每次访问还去数据库里读一下,然后拿出来对 ...
可以这样,既然是要先判断是否存在预编译文件,然后再决定是否链接数据库查询是否有最新更新,那么为何不在数据更新的时候就重新创建预编译文件或者说清除这些过期的缓存呢

一般来说,缓存文件都会指定一个存活周期的,当系统被告知这个缓存文件已经过期,不管你数据库的数据是否有改动,都会重新查询一次数据库并创建最新的缓存文件,或者是另外一种方案,那就是主动创建,当数据库数据发生变动时,删除所关联的缓存文件
僭燮水 at 2008-9-22 18:15:18

QUOTE:

原帖由 phpe 于 2008-9-22 17:20 发表

如果预编译的文件已存在,但是数据库里面的内容有改动,这个时候怎么办?
是不是检查一下有没有更新?如果有就重新预编译!如果没有就直接包含?
我就是不明白这一点,每次访问还去数据库里读一下,然后拿出来对 ...
这么老的帖子都被顶起来了。。。。

QUOTE:

这是我在blog上给你的回复,当时没看到你的引用。
@phpe 这个是做缓存的,比如十分钟更新,如果预编译的文件没有达到10分钟,就不会重新生成,另外可以通过特定的操作进行出发,关于缓存这块,你可以看看MooPHP框架中如何实现的

新的回复如下:
Discuz!是把templates/default中的模版文件,预编译,也就是在请求访问index.php文件的时候,程序先在forumdata/templates中是否已经生成预编译的文件,
这个并不涉及数据库缓存的,只是模板的预编译过程。
僭燮水 at 2008-9-22 18:16:06

QUOTE:

原帖由 xinzf 于 2008-9-22 18:11 发表

一般来说,缓存文件都会指定一个存活周期的,当系统被告知这个缓存文件已经过期,不管你数据库的数据是否有改动,都会重新查询一次数据库并创建最新的缓存文件,或者是另外一种方案,那就是主动创建,当数据库数据发生变动时,删除所关联的缓存文件
正解,两种情况:
a.比如MooPHP框架中的block缓存就是采用存活期控制。
b.MooPHP框架中的cache缓存是采用主动删除关联缓存文件的方式。

[ 本帖最后由 僭燮水 于 2008-9-22 18:17 编辑 ]
phpe at 2008-9-23 11:42:55
还有一问题!这两天一直都在看dz的代码
下面分别是 forumdisplay.php viewthread.php 文件所有查询数据库的SQL语句
[php]
forumdisplay.php(贴子列表)

SELECT sid, uid AS sessionuid, groupid, groupid='6' AS ipbanned, pageviews AS spageviews, styleid, lastolupdate, seccode FROM jsb_sessions WHERE sid='6mpwek' AND CONCAT_WS('.',ip1,ip2,ip3,ip4)='192.168.0.254'

SELECT f.fid, f.*, ff.* , f.fid AS fid FROM jsb_forums f LEFT JOIN jsb_forumfields ff ON ff.fid=f.fid WHERE f.fid='8'

SELECT t.* FROM jsb_threads t WHERE t.tid IN (66) AND t.displayorder IN (2, 3) ORDER BY displayorder DESC, lastpost DESC LIMIT 0, 1

SELECT t.* FROM jsb_threads t WHERE t.fid='8' AND t.displayorder IN (0, 1) ORDER BY displayorder DESC, lastpost DESC LIMIT 19

UPDATE jsb_sessions SET uid='0', username='', groupid='7', styleid='1', invisible='0', action='2', lastactivity='1222140457', lastolupdate='0', seccode='209771', fid='8', tid='0', bloguid='0' WHERE sid='6mpwek'
[/php]

[php]
viewthread.php(贴子正文)

SELECT sid, uid AS sessionuid, groupid, groupid='6' AS ipbanned, pageviews AS spageviews, styleid, lastolupdate, seccode FROM jsb_sessions WHERE sid='6mpwek' AND CONCAT_WS('.',ip1,ip2,ip3,ip4)='192.168.0.254'

SELECT t.tid, t.closed, t.dateline, t.special, t.lastpost AS lastthreadpost, f.*, ff.* , f.fid AS fid FROM jsb_threads t INNER JOIN jsb_forums f ON f.fid=t.fid LEFT JOIN jsb_forumfields ff ON ff.fid=f.fid WHERE t.tid='38' AND t.displayorder>='0' LIMIT 1

SELECT * FROM jsb_threads t WHERE tid='38' AND displayorder>='0'

SELECT uid AS moduid, username AS modusername, dateline AS moddateline, action AS modaction, magicid FROM jsb_threadsmod WHERE tid='38' ORDER BY dateline DESC LIMIT 1

SELECT tagname FROM jsb_threadtags WHERE tid='38'

UPDATE LOW_PRIORITY jsb_threads SET views=views+1 WHERE tid='38'

SELECT p.*, m.uid, m.username, m.groupid, m.adminid, m.regdate, m.lastactivity, m.posts, m.digestposts, m.oltime, m.pageviews, m.credits, m.extcredits1, m.extcredits2, m.extcredits3, m.extcredits4, m.extcredits5, m.extcredits6, m.extcredits7, m.extcredits8, m.email, m.gender, m.showemail, m.invisible, m.xspacestatus, mf.nickname, mf.site, mf.icq, mf.qq, mf.yahoo, mf.msn, mf.taobao, mf.alipay, mf.location, mf.medals, mf.avatar, mf.avatarwidth, mf.avatarheight, mf.sightml AS signature, mf.customstatus, mf.spacename FROM jsb_posts p LEFT JOIN jsb_members m ON m.uid=p.authorid LEFT JOIN jsb_memberfields mf ON mf.uid=m.uid WHERE p.tid='38' AND p.invisible='0' ORDER BY dateline LIMIT 0, 10
[/php]
貌似这些东西都没有缓存呀,DZ缓存的只是很常用的东西,贴子列表,贴子正文都不见缓存,而是每次刷新都在查数据库
我想问的是,他为什么不缓存这些内容!为什么在很高的访问量下还可以这么快!·
phpe at 2008-9-23 12:04:20
另外,还发现在个事儿!

比如说现在我在论坛里开了一个版块叫 '聊天的到这里来'
当我刷新首页是,出现了 '聊天的到这里来' 的这样一版块!
然后我去forumdata目录下查看文件内容,发现有三个文件记录着有关 '聊天的到这里来' 这样的内容
[php]
cache_forumdisplay.php
  array (
    'fid' => '6',
    'type' => 'forum',
    'name' => '聊天的到这里来',
    'fup' => '5',
    'viewperm' => '',
    'orderby' => 'lastpost',
    'ascdesc' => 'DESC',
  ),
...
cache_forums.php
  6 =>
  array (
    'fid' => '6',
    'type' => 'forum',
    'name' => '聊天的到这里来rrrrrrrr',
    'fup' => '5',
    'viewperm' => '',
    'orderby' => 'lastpost',
    'ascdesc' => 'DESC',
  ),
...
cache_viewthread.php
  array (
    'fid' => '6',
    'type' => 'forum',
    'name' => '聊天的到这里来',
    'fup' => '5',
    'viewperm' => '',
    'orderby' => 'lastpost',
    'ascdesc' => 'DESC',
  ),
[/php]

接着,我打开记事本,将这三个文件的
'name' => '聊天的到这里来',
修改成
'name' => '聊天的到这里来被我修改后',
保存,然后再刷新首页!之前那个版块名仍然是 '聊天的到这里来',并没有被修改
这是为什么呢?
接我找到数据库这一内容,改掉后,刷新首页,结果变了,

我想问问,那么他缓存起来,准备什么时候用啊。
hobbs136 at 2008-9-23 12:18:20
我发的一个帖子,在基础区没人点评,请大家看看,点评一下。
我的初衷是--不需要担心缓存小文件过多而导致的inode不够用的问题。
http://bbs.phpchina.com/thread-80737-1-1.html
phpe at 2008-9-23 12:25:49
顶上去,让更多的人看到!

[ 本帖最后由 phpe 于 2008-9-23 13:31 编辑 ]
yesin at 2008-9-23 15:29:29
后面写着写着怎么笔锋一转,骂开了?
phpe at 2008-9-25 08:20:48

QUOTE:

原帖由 yesin 于 2008-9-23 15:29 发表
后面写着写着怎么笔锋一转,骂开了?
???
ginux at 2008-12-17 04:59:25
学习