当前位置: > Linux服务器 > nginx >

nginx缓存清理,php批量清除nginx缓存的方法

时间:2015-03-14 22:34来源:jbxue.com 作者:IT
如何清理nginx缓存?nginx作为缓存服务器时,定期清理缓存是个好习惯,这里分享一例用于批量清理nginx缓存的php脚本代码。

使用nginx的proxy_cache模块做缓存服务器,由于由于修改比较多,每次使用ngx_cache_purge清除cache只能清除几个url,没有很好的办法去清除某个目录的缓存。

研究了nginx的缓存文件格式,发现可以从中提取出url出来,如下图所示,url是以"KEY:"开头以0x0A结尾:

nginx缓存清理,php批量清除nginx缓存的方法

用php程序实现(shell脚本实现方法,参考链接:nginx缓存管理 shell脚本批量清除nginx缓存代码):
1,提交一批url进行清除对应的cache
2,提交一批url目录可以清除包含这些目录的url,若是提交域名可以清除整站
3,查看某个目录下的缓存文件是否缓存上
4,可以添加多个站点

记得先安装ngx_cache_purge才可以哦。

php代码(php批量清除nginx缓存的方法):
 

复制代码代码示例:

<?php
/*
*
功能:按照多个目录或者多个URL的方式,清除nginx的cache,或者查看nginx cache 缓存
要求:nginx + ngx_cache_purge
*/
//代理服务器的ip
$proxyIp="127.0.0.1";
//代理服务器端口
$proxyPort=80;
//代理服务器的缓存目录
$cacheDir="/opt/proxy_cache_dir/";
$proxySites=array(
//用户访问的域名 => 被代理的实际网站的域名,若是都是80的话就是一样即可
"http://www.test.com"=>"http://www.test.com"
);
//输出文件
$output="";
$result=array();
$filedirs = array();
//只查看缓存文件,不清除
if($_POST["view"]){
$accessSite=$_POST["accessSite"];
$proxySite=$proxySites[$accessSite];
$clearUrls=array();
$clearUrls=explode ("\n",$_POST["dirs"]);
if($$proxySite){
foreach($ds as $d){
$d=str_replace($accessSite, $proxySite,$d);
$clearUrls[]=$d;
}
}
scan_dir($cacheDir);
$cacheurls = array();
foreach($filedirs as $filename){
if(!is_file($filename)){
continue;
}
$cacheUrl=getUrlFromCacheFile($filename);
if(count($clearUrls)){
$cacheurls[]=$cacheUrl;
continue;
}
foreach($clearUrls as $clearUrl){
$clearUrl=str_replace($accessSite, $proxySite,$clearUrl);
$pos=strpos($cacheUrl,$clearUrl);
// echo "$cacheUrl,$clearUrl,$pos<br/>";
//比较http://www.b.com/a/b.jpg和http://www.b.com/a
if($pos===0){
$cacheurls[]=$cacheUrl;
break;
}
}
}

}else //清除一批URL
if($_POST["urls"]){
$accessSite=$_POST["accessSite"];
$proxySite=$proxySites[$accessSite];
$output.="<div style='font-size:16px;font-weight:bold'>执行结果
\n<pre>\n";
$urls=explode ("\n",$_POST["urls"]);
foreach($urls as $url2){
$url=trim($url2);
$output.="------------------------$url start-----------------------------\n";
$pos = strpos($url, $accessSite);
if ($pos !== false && $pos==0) {
$url=str_replace($accessSite, $proxySite,$url);
if(purge($proxyIp,$proxyPort,$url)==0){
$result[$url2]=0;
}else{
$result[$url2]=1;
}
}else{
$output.="skip $url\n";
$result[$url2]=-1;
}
$output.="------------------------$url end -----------------------------\n";
}
$output.="</pre>\n";
}else//清除某个目录下的所有文件
if($_POST["dirs"]){
$accessSite=$_POST["accessSite"];
$proxySite=$proxySites[$accessSite];
$clearUrls=array();
$clearUrls=explode ("\n",$_POST["dirs"]);
if($$proxySite){
foreach($ds as $d){
$d=str_replace($accessSite, $proxySite,$d);
$clearUrls[]=$d;
}
}
scan_dir($cacheDir);
$cacheurls = array();
foreach($filedirs as $filename){
if(!is_file($filename)){
continue;
}
$cacheUrl=getUrlFromCacheFile($filename);

foreach($clearUrls as $clearUrl){
$clearUrl=str_replace($accessSite, $proxySite,$clearUrl);
$pos=strpos($cacheUrl,$clearUrl);
// echo "$cacheUrl,$clearUrl,$pos<br/>";
//比较http://www.b.com/a/b.jpg和http://www.b.com/a
if($pos===0){
$cacheurls[]=$cacheUrl;
break;
}
}
}
if(count($cacheurls) > 0){
$accessSite=$_POST["accessSite"];
$proxySite=$proxySites[$accessSite];
$output.="<div style='font-size:16px;font-weight:bold'>执行结果
\n<pre>\n";
foreach($cacheurls as $url2){

$url=trim($url2);
$output.="------------------------$url start-----------------------------\n";
$pos = strpos($url, $accessSite);
if(purge($proxyIp,$proxyPort,$url)==0){
$result[$url2]=0;
}else{
$result[$url2]=1;
}
$output.="------------------------$url end -----------------------------\n";
}
$output.="</pre>\n";
}else{
foreach($clearUrls as $u){
$result[$u]=-1;
}
}
}
?>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>刷新squid</title>
<body>
<?php
if($result){
echo "<table border='1'><tr><td>URL</td><td>结果</td></tr>\n";
foreach($result as $url=>$isOk){
switch($isOk){
case 0://成功
$r="<font style='color:#90EE90'>成功</font>";
break;
case 1://成功
$r="<font color='red'>失败</font>";
break;
case -1://跳过
$r="<font color='Yellow'>跳过</font>";
break;
}
if($$proxySite){
$url=str_replace($proxySite, $accessSite, $url);
}
echo "<tr><td>$url</td><td>$r</td></tr>\n";
}
echo "</table>\n";
}
?>

<form action="" method="post">
<table >
<tr><td>选择站点:</td></tr>
<tr><td>
<select name="accessSite" id="accessSite">
<?php
foreach($proxySites as $accessSite => $proxySite){
$isSelected=$_POST["accessSite"]==$accessSite?"selected":"";
echo "<option value='$accessSite' $isSelected>$accessSite</option>\n";
}
?>
</select>
<script>
function view(){
location="?accessSite="+document.getElementById("accessSite").value+"&view=1";
}
</script>
<input type="checkbox" name="view" value="1" <?php echo $_POST["view"]?"checked":"";?>/><label for="view">只查看</label>
</td></tr>
<tr><td>输入一组URL(一个一行):</td></tr>
<tr><td><textarea name="urls" style="width:1000px;height:200px;"><?php if($_POST["view"])foreach($cacheurls as $cacheurl){echo "$cacheurl\n";}?></textarea></td></tr>
<tr><td>刷新目录(一个一行):</td></tr>
<tr><td><textarea name="dirs" style="width:1000px;height:200px;"></textarea></td></tr>
<tr><td><input type="submit" value="提交" /></td></tr>
</table>
</form>
<?php
echo $output;
?>
</body></html>
<?php
//清除某个url
function purge($proxyIp,$proxyPort,$url)
{
global $output;
$host = parse_url($url);
$host = $host['host'];
$purge_url=str_replace("http://".$host,"/purge",$url);
if (empty($proxyIp)) {
$proxyIp = gethostbyname($host);
}
if (empty($proxyPort)) {
$proxyPort = "80";
}
$output.="正在从服务器".$proxyIp."更新".$url."\n";
$errstr = '';
$errno = '';
$fp = fsockopen ($proxyIp, $proxyPort, $errno, $errstr, 2);
if (!$fp)
{
$output.="连接失败!";
return -1;
}
else
{
$out = "GET ".$purge_url." HTTP/1.1\r\n";
$out .= "Host:".$host."\r\n";
$out .= "Connection: close\r\n\r\n";
$output.="***********request start**************\n";
$output.=$out;
$output.="***********request end **************\n";
fputs ($fp, $out);
$output.="***********response start**************\n";
//是否更新成功
$isOk=false;
while($out = fgets($fp , 4096)){
if(strpos($out,"200 OK\r\n")!==FALSE){
//更新成功
$isOk=true;
}
$output.=$out;
if($out=="\r\n"){
break;
}
}
fclose ($fp);
$output.="***********response end **************\n"; 
flush();
if($isOk){
return 0;
}else{
return 1;
}
}
}

//递归扫描cache目录下所有文件路径
function scan_dir($dir) {
global $filedirs;
if (!is_dir($dir)) return false;
if ($dh = opendir($dir)) {
while (($file = readdir($dh)) !== false) {
if ($file[0] == '.') continue;
if($file=='swap.state')continue;
$fullpath = "$dir/$file";
$filedirs[] = $fullpath;
if (is_dir($fullpath)) 
scan_dir($fullpath); 
}
closedir($dh);
}
return $filedirs;
}
//从cache文件中提取真实的URL
function getUrlFromCacheFile($filename){
//cache文件头长度
$headerLen=0x1E;
$handle = fopen($filename, "rb");
if(!$handle){
return -1; 
}
//读取文件的前1k字节
$contents = fread($handle, 1024);
fclose($handle);
if(strlen($contents)<=$headerLen){
return -2; 
}
//截掉文件头
$contents=substr($contents,$headerLen);

//cache文件的分隔符为\A
$pos=strpos($contents, chr(0x0A));
if($pos===FALSE){
return -3; 
}
//获取分隔符前的字符串
$contents="http://".substr($contents,0,$pos);
return $contents;
}
?>


测试结果:
nginx缓存清理,php批量清除nginx缓存的方法


nginx缓存批量清除三种方式

1,原始的只增加缓存模块的,根据访问的路径一条条清除。
根据此方式要进行批量清除的话,必须在设定的缓存目录下通过自己写的程序来读取nginx文件中的配置,然后根据配置文件中的路径查找缓存文件,找到配置的缓存文件,并索引,然后根据索引的缓存路径值执行单个文件清除。

此方法,大量时间耗费在缓存文件的查找上,当文件上G的时候就很慢,文件越多速度越慢。
还有一个脚本实现方式在此 nginx-cache-purge,里面用了并行的查找相对快点,不过速度还是慢。

2,修改缓存代码,实现按域名(可以适当加路径)来缓存,这样可以快速定位到需要的文件夹中进行批量清除。
此方法,只是在缓存文件的路径前增加了一个域名目录,其他操作和第一种类似 ,这样可以大大提高速度。至少不用全局搜索。

相应的代码 在此有说明 Nginx配置缓存,按域名存放。如果增加了域名下的目录的话可能会更快一点,但是感觉会影响性能,本人测试了一下,在域名 + 5级目录的情况下一般可以正常访问,只是有时候会出现访问不了的情况,不过刷新一下就可以。不过要增加文件目录为缓存路径的话必须考虑uri中的特殊字符和linux系统文件路径长度的问题。

3,也是修改代码 生成一个group key来缓存同一类型的文件,清除的时候可以根据groupkey来缓存。
这个是一个外国人写的补丁,可以设定某个关键字来清除。可以根据需要灵活设定。相应的说明在此 Nginx cache grouped by keys 。这个配置比较灵活,可以根据需要设定,例如也可以配置一下,根据目录来缓存,但一个文件只能有一种类型的groupkey。因此要是设置了父目录为groupkey的话,再设置子目录就会根据子目录来进行groupkey。因此,可以实现的是根据每个目录来缓存,清除的时候只能一次清除一个目录的文件,要想清除整个域名下的缓存的话就得所有目录的缓存清除了。

要想即实现能一次清除整个域名下的目录又能在需要的时候清除某个一个具体目录下的文件,或清除单个文件这个有点麻烦??

可以通过修改代码实现带*通配符的指删除,先将文件移动 到一个目录后再清除 ,这样能表面上实现瞬间的清除,删除工作在后台进行着。
还有要是直接把缓存路径中的目录删除的话会对访问有影响?内存中的值会被释放?里面的红黑树会变化?

 


(责任编辑:IT)
------分隔线----------------------------
栏目列表
推荐内容