现在的位置: 首页 > 软件开发 > 正文

解决discuz更新缓存cpu占用高的问题

2010年11月20日 软件开发 ⁄ 共 1595字 暂无评论 ⁄ 被围观 499+

每次在后台更新模板缓存或手动修改header等模板后,服务器cpu飙升到100%,并且一直持续很长时间直至无法忍耐重启iis数次后才能平复。(重启一两次还没有cpu还是100%)

这个问题一直困扰了很长时间,在官方和网上都没有找到解决方案(官网上看到有人反应dz7.0下也有这个问题)。今天抽出一天时间好好跟踪了一下这个问题。

首先看看discuz模板相关的2个关键函数:include\\global.func.php中的checktplrefresh函数和include\\template.func.php中的parse_template函数

checktplrefresh函数:判断目标模板是否存在或过期(目标模板所依赖的子模板header等修改时间大于目标模板修改时间),若不存在或过期则调用parse_template重新生成目标模板

parse_template函数:将templates\\default(默认模板)\\**.htm模板文件解析转化成php模板文件

通过跟踪调试发现:

当目标模板需要更新时,如果只有1个用户访问parse_template函数,1秒钟不到即可执行结束,成功生成新的目标模板。

当同时访问的用户增加时parse_template函数花费的时间成指数级上涨(到底什么指数就不考究了),当有10多个用户同时访问同一个网页导致同时更新该目标模板时,每个用户执行parse_template函数平均需要150~200秒。问题出来了php默认脚本超时时间为30秒,可见没有1个用户能够执行完parse_template函数生成出新的目标模板。同时新的访问请求不断到达又占用cpu资源,这就导致cpu一直居高不下。一直在试图生成新的目标模板但一直没能成功。

试着增大php脚本超时时限也没能解决问题,增大了该时限,意味着会有更多的请求来执行parse_template函数导致消耗更多的cpu资源,反而是恶性循环。

看来关键问题是:当需要更新模板时,如何防止重入parse_template函数

做了如下改进,经过几次测试发现更新缓存后情况大为好转,短暂的时间内用户访问会发现较慢,几秒钟后即可恢复正常。

在forumdata下新建文件夹lock用来存临时锁文件

function parse_template($tplfile, $templateid, $tpldir) {
	global $language, $subtemplates, $timestamp;

	$nest = 5;
	$file = basename($tplfile, \'.htm\');
	$objfile = DISCUZ_ROOT."./forumdata/templates/{$templateid}_$file.tpl.php";
	
	//新增
	$objfile_lock = DISCUZ_ROOT."./forumdata/lock/{$templateid}_$file.tpl.php";
	$timeObjFile = @filemtime($objfile);
	$timeLockFile = @filemtime($objfile_lock);
	while(!empty($timeLockFile) && (time()-$timeLockFile)<30){
		$nowtimeObjFile = @filemtime($objfile);
		if(!empty($nowtimeObjFile)){
			if(empty($timeObjFile) || $nowtimeObjFile>$timeObjFile){
				return;
				//break;
			}
		}		
		sleep(1);
	}
	@fopen($objfile_lock, \'w\');

	//原内容不变

	//新增
	@unlink($objfile_lock);
}

改进后可以减少重入数量、降至cpu占用率。

给我留言

您必须 [ 登录 ] 才能发表留言!

×
#