Linux / PHP文件访问问题(构建自定义缓存)

时间:2014-02-18 04:39:48

标签: php rhel5

我有一个小问题,希望有人可以了解情况。

情况:

我有一个内置于PHP CMS中的自定义部分缓存机制。简而言之,当处理CMS中的模板时,它处理'cachable'PHP代码并且不处理'不可缓存的'php代码,然后将生成的代码保存为要处理的文件以供将来访问页。

问题:

当系统“查找”缓存文件时,我遇到文件访问延迟。使用GLOB查找匹配文件的250,000个缓存文件在网站上没有流量时需要1/4秒 - 有时流量峰值为10-15秒。几乎看起来两个单独的客户端会话不能同时运行GLOB,因此它们瓶颈。

我在寻找什么:

...是一种替代方法,或提供块缓存的优化,没有瓶颈问题。必须考虑我的独特顾虑(概述如下)。我需要一种更快的方式来访问这些文件或另一个部分页面缓存方向:/

============================================== < / p>

ABRIDGED CODE:

// var to hold cached page path, if found
$pageCache = NULL;

// get the URL for current page
// there is actually some other code here that could alter the 'theURL4Cache' var for various reasons, but for simplicity in this example lets just keep it the REQUEST_URI
$GLOBALS['theURL4Cache'] = $_SERVER['REQUEST_URI'];

// check if existing cache file is in place
$filePattern = 'parsed/page_cache/*^' . $_SERVER['SERVER_PORT'] . '^' . $_SERVER['HTTP_HOST'] . '^' . (($_SESSION['isMobile']) ? 'M' : 'D') . '^L' . $language . '^T*^P' . $attributes['pageId'] . '^' . md5($GLOBALS['theURL4Cache']) . sha1($GLOBALS['theURL4Cache']) . '.php';
$fileArr = glob($filePattern);

// possible multiple files found that fit / expired files found that fit the pattern
// lets grab the newest file and try to use it
if(count($fileArr)){ 
        rsort($fileArr);
        $file = $fileArr[0]; // get file with latest expire date
        if($file > 'parsed/page_cache/' . date('Y-m-d-H-i-s')) $pageCache = $file; // set an attribute to hold the valid file path to the cached file
        // remove files that are no longer corrent
        for($i=(($pageCache === NULL) ? 0 : 1); $i<count($fileArr);$i++) unlink($fileArr[$i]);
    };
if($pageCache){
  // cached page is found, lets process and output this puppy
  include($pageCache);
} else {
  // cached page is not found, let's build a cacheable page from the CMS template
  $newCode = // ..... various code is processed here to isolate the cacheable code blocks and process while leaving the non-cacheable blocks intact ..... //
  // create the new file path where the cached code will be placed
  // first we need an expiration date
  $cacheDate = date_create();
  date_add($cacheDate, date_interval_create_from_date_string( $cache_increment . ' ' . $cache_interval)); // $cache_increment and $cache_interval are stored in the CMS DB for each page, giving the content manager control over the expiration of the page in cache
  $filePath = $GLOBALS['iProducts']['physicalRoot'] . "/parsed/page_cache/" . date_format($cacheDate,'Y-m-d-H-i-s') . "^" . $_SERVER['SERVER_PORT'] . '^' . $_SERVER['HTTP_HOST'] . '^' . (($_SESSION['isMobile']) ? 'M' : 'D') ."^L" . $language . "^T" . $templateId . "^P" . $attributes['pageId'] . "^" .md5($GLOBALS['theURL4Cache']) . sha1($GLOBALS['theURL4Cache']) . '.php'; // create the file path
  if(file_exists($filePath)) unlink($filePath); // delete the file if it already exists
  $fp = fopen($filePath,"w"); // create the new file
  flock($fp,LOCK_EX);
  fwrite($fp,$newCode); // write the cache file
  flock($fp,LOCK_UN);
  // now output this puppy
  eval($newCode);
};

为什么你的文件是什么样的,你问的是什么?

嗯,我很高兴你问过! CMS的另一部分包括“智能缓存管理”,其中如果页面或模板被内容管理器修改,则所有缓存的页面都将从系统中清除。此外,页面中的内容可能会因URL查询字符串中的attribs而异,如果它是移动设备呈现,SSL与非SSL,域名或当前会话语言(引擎支持多种语言内容)与同一页面相关联,根据会话语言有条件地输出。

所以这是一个缓存的页面文件名示例: 2014-02-14-10-36-36 ^ 80 ^ www.mydomain.com ^ M ^ L ^ T42 ^ P41 ^ a067036ef358f12a0049740f035a7ee688dbb0033c19a70163d6c453dbc5b84f1889ffe2.php

以下是文件名的组成部分: 到期最新^端口^域^ mobileOrDesktop ^语言^模板^页^ MD5 + sha1OfURL.php

以下是解释的组件:

  • expire-date:此缓存文件应根据CMS中的内容管理员条目计算的计算日期/时间。 GLOB可以使用它来过滤掉所有过期的文件,并通过CRON作业删除它们以进行清理。这也是为了确定缓存页面是否足够新鲜以显示在代码的开头。
  • port:80或443表示是否通过SSL检索到此内容。根据SSL状态,内容可能会有条件地不同。
  • 域名:“www.mywebsite.com”可以将多个域名附加到CMS安装,需要区分,因此具有相同REQUEST_URI的两个域不会显示彼此的内容
  • 移动或桌面:“M”或“D” - 允许相同的网址“嗅出”客户端并相应地提供内容。
  • 语言:如果不使用多种语言则为“L”,如果使用多语言则为“L-ENG / L-GER / ...”
  • 模板:“T#”因此templateId 47将为“T47” - 允许按文件名轻松过滤,以使用给定模板识别所有缓存页面,以便在CMS中修改模板时删除。
  • page:“P#”所以pageId 12将是“P12” - 允许按文件名轻松过滤,以识别在CMS中修改页面时要删除的给定页面的所有缓存版本。
  • md5 + sha1OfURL.php:接受$ _SERVER ['REQUEST_URI']并将其编码为TWICE(一次是MD5,一次是SHA1),将结果连接起来,得到一个(合理的)唯一ID表示URL(因为查询字符串可以影响内容)

欢迎任何想法或建议。提前谢谢!

1 个答案:

答案 0 :(得分:0)

一些想法:

  1. 您可能需要考虑内存缓存系统,例如memcached或redis,而不是磁盘上的缓存系统。读取和写入磁盘的负载可能很大。

  2. 有模板引擎(如SMARTY http://www.smarty.net/)会为你做很多繁重的工作。

  3. 您应该使用一致的哈希规则来保存文件名,然后使用标记的二级哈希值,而不是使用globs来搜索目录。例如,保存所有文件:

    $fname = sha1($GLOBALS['theURL4Cache'].ALL_THE_REST_OF_THOSE_VARIABLES);
    $cachedir1 = substr($fname ,0,1);
    $cachedir2 = substr($fname,0,2);
    $finalname = 'parsed/page_cache/' . $cachedir1 . '/' .$cachedir2 .'/'. $fname . '.php';
    
  4. 这意味着一个sha1为abcdefgh的文件将保存为'parsed / page_cache / a / ab / abcdefgh.php'。这有助于减少文件系统性能下降。

    现在,只要您知道文件名,就能找到该文件 - 基本上您将目录路径用作大型哈希表。对于您的标签,设置另一组哈希 - 这些哈希可以保存为磁盘或数据库或内存中的文件。每当将页面添加到其中一个标记时,请将sha1摘要或文件名添加到相应的哈希中。例如,在一个名为'parseHashes / is_mobile.php'的文件中,你可以有一个像

    这样的数组
    $arr = array(
        "abcd",
        "defg"
       );
    

    每个键都是您需要查找和/或删除的sha1摘要。当您需要操作标记中的文件集时,您可以迭代存储的sha摘要,并且您知道在哪里可以找到文件内容。

    所有这一切,您应该真正研究基于内存或甚至数据库的解决方案。在filesytem上执行此操作需要做很多工作,并且不能很好地扩展。