|
本帖最后由 hulei0102 于 2012-1-27 21:53 编辑
首先问题是这样,我有个站大约200万数据,全站文件缓存。我一直用的是CI的文件缓存机制,考虑到磁盘性能问题我会定期(每天)清除一下文件缓存。但是现在问题来了,就这几天引擎搜索暴增每天大约产生10W左右的页,这样一来CI文件缓存机制直接崩溃!!!直接的后果就是用户浏览页面速度直接慢过不用缓存,删除cache文件夹用了我半个小时TT 于是我终于下定决心改进CI_Output的缓存机制。
首先搜索了一下老贴,发现已有很多前辈提出了问题,并有了解决方案:
脆弱的CI缓存系统,1天攻陷你的CI网站
http://codeigniter.org.cn/forums/forum.php?mod=viewthread&tid=16901
CI缓存终极解决思路
http://codeigniter.org.cn/forums/forum.php?mod=viewthread&tid=2527
看了《CI缓存终极解决思路》这一帖,发现思路很不错,但是没有现成的代码,所以我依照这贴思路改进了CI_Output。
原理如下:
取Cache文件名md5码的后2位,生成目录存放缓存
因为C(36,2) = 630,也就是说总共生成630个文件夹,2000000/630 = 3174 ,这样就会吧所有缓存数据分散到各个目录提高索引速度。
CI版本2.1.0,代码如下,只需新建Application\core\My_Output.php,只扩展_write_cache、_display_cache2个函数即可达到目的,代码如下:
PHP复制代码
class MY_Output extends CI_Output
{
//$param=1写入文件缓存 $param=0读取文件缓存
function breakup_cachefiles ($cache_path,$param=1)
{
$ret = '';
/*1、取得md5码的后2个字母,目的是分散缓存到不同的文件夹,使磁盘能够更快索引
substr($cache_path, -3) C(36,3) = 7140(排列组合数),磁盘可以承受再大就不行了
*/
$md5_2 = substr($cache_path, -2);
//echo '<font color=blue>'.$md5_2.'<font>';
//2、建立目录名=$md5_2的目录
$dir = dirname($cache_path);//获取当前目录名
$file = basename($cache_path);//获取当前文件名
$newdir = $dir.'/'.$md5_2;//新的目录名
if($param==1)
{
if (!file_exists($newdir))//目录不存在则创建
mkdir($newdir,0777);
}
//3、将 $cache_path 定位到新的文件夹
$ret = $newdir.'/'.$file;
return $ret;
}
// --------------------------------------------------------------------
/**
* Write a Cache File
*
* @access public
* @param string
* @return void
*/
function _write_cache ($output)
{
$CI =& get_instance ();
$path = $CI->config->item('cache_path');
$cache_path = ($path == '') ? APPPATH .'cache/' : $path;
if ( ! is_dir($cache_path) OR ! is_really_writable ($cache_path))
{
log_message ('error', "Unable to write cache file: ".$cache_path);
return;
}
$uri = $CI->config->item('base_url').
$CI->config->item('index_page').
$CI->uri->uri_string();
$cache_path .= md5($uri);
/*生成Md5缓存文件后处理*/
$cache_path = $this->breakup_cachefiles($cache_path,1);
if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE ))
{
log_message ('error', "Unable to write cache file: ".$cache_path);
return;
}
$expire = time() + ($this->cache_expiration * 60);
if (flock($fp, LOCK_EX ))
{
fwrite($fp, $expire.'TS--->'.$output);
flock($fp, LOCK_UN );
}
else
{
log_message ('error', "Unable to secure a file lock for file at: ".$cache_path);
return;
}
fclose($fp);
@chmod($cache_path, FILE_WRITE_MODE );
log_message ('debug', "Cache file written: ".$cache_path);
}
// --------------------------------------------------------------------
/**
* Update/serve a cached file
*
* @access public
* @param object config class
* @param object uri class
* @return void
*/
function _display_cache (&$CFG, &$URI)
{
$cache_path = ($CFG->item('cache_path') == '') ? APPPATH .'cache/' : $CFG->item('cache_path');
// Build the file path. The file name is an MD5 hash of the full URI
$uri = $CFG->item('base_url').
$CFG->item('index_page').
$URI->uri_string;
$filepath = $cache_path.md5($uri);
/*生成Md5缓存文件后处理*/
$filepath = $this->breakup_cachefiles($filepath,0);
if ( ! @file_exists($filepath))
{
return FALSE;
}
if ( ! $fp = @fopen($filepath, FOPEN_READ ))
{
return FALSE;
}
flock($fp, LOCK_SH );
$cache = '';
if (filesize($filepath) > 0)
{
$cache = fread($fp, filesize($filepath));
}
flock($fp, LOCK_UN );
fclose($fp);
// Strip out the embedded timestamp
if ( ! preg_match("/(\d+TS--->)/", $cache, $match))
{
return FALSE;
}
// Has the file expired? If so we'll delete it.
if (time() >= trim(str_replace('TS--->', '', $match['1'])))
{
if (is_really_writable ($cache_path))
{
@unlink($filepath);
log_message ('debug', "Cache file has expired. File deleted");
return FALSE;
}
}
// Display the cache
$this->_display (str_replace($match['0'], '', $cache));
log_message ('debug', "Cache file is current. Sending it to browser.");
return TRUE;
}
}
// END class MY_Output
复制代码
就这么简单!最后附上My_Output.php,祝各位新年快乐{:soso_e128:}最后希望,CI官方在下一个版本能够彻底解决文件cache机制带来的这种烦恼,让大家不再用这种方式去解决问题了。
My_Output.zip
(1.77 KB, 下载次数: 138)
|
|