【问题标题】:How to cache dynamic PHP page如何缓存动态PHP页面
【发布时间】:2011-04-16 18:32:25
【问题描述】:

如何缓存有 mysql 查询的 PHP 页面。任何示例都会非常有用。

【问题讨论】:

  • 是否要集成 HTTP 缓存?

标签: php caching


【解决方案1】:

我正在使用phpFastCache(对于共享主机,如果您不想触摸 php.ini 和 root 来设置 memcached)。查看示例菜单。他们有完整的详细示例,而且非常简单。

首先使用 phpFastCache::set 设置,然后使用 phpFastCache::get 获取 - 完成!

示例:减少数据库调用

您的网站有 10,000 名在线访问者,您的动态页面必须在每次页面加载时向数据库发送 10,000 个相同的查询。使用 phpFastCache,您的页面仅向数据库发送 1 个查询,并使用缓存为其他 9,999 个访问者提供服务。

<?php
    // In your config file
    include("php_fast_cache.php");
    phpFastCache::$storage = "auto";
    // you can set it to files, apc, memcache, memcached, pdo, or wincache
    // I like auto

    // In your Class, Functions, PHP Pages
    // try to get from Cache first.
    $products = phpFastCache::get("products_page");

    if($products == null) {
        $products = YOUR DB QUERIES || GET_PRODUCTS_FUNCTION;
        // set products in to cache in 600 seconds = 5 minutes
        phpFastCache::set("products_page",$products,600);
    }

   OUTPUT or RETURN your $products
?>

【讨论】:

【解决方案2】:

我的偏好是使用缓存反向代理,例如Varnish

就纯 PHP 解决方案而言,您可以在脚本末尾添加一些代码来缓存最终输出,并在开头添加一些代码来检查页面是否被缓存。如果在缓存中找到该页面,请将其发送并退出,而不是再次运行查询。

<?php

function cache_file() {
    // something to (hopefully) uniquely identify the resource
    $cache_key = md5($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']);
    $cache_dir = '/tmp/phpcache';

    return $cache_dir . '/' . $cache_key;
}

// if we have a cache file, deliver it
if( is_file( $cache_file = cache_file() ) ) {
    readfile( $cache_file );
    exit;
}

// cache via output buffering, with callback
ob_start( 'cache_output' );

//
// expensive processing happens here, along with page output.
//

function cache_output( $content ) {
    file_put_contents( cache_file(), $content );
    return $content;
}

显然,这需要对您的设置进行大量自定义,包括缓存过期、满足您需求的 $cache_key 以及错误检测,因此不会缓存不良页面。

【讨论】:

  • 你在哪里打电话给cache_output
  • @AakilFernandes 输出缓冲区在请求结束时有一个隐式刷新。 ob_start() 指定 cache_output() 作为其回调。所以,最后的隐式刷新调用cache_output()
【解决方案3】:

memcache 你的 html 出来,然后做这样的事情:

$memcache = memcache_connect('localhost', 11211);

$page  = $memcache->get('homepage');
if($page == ""){
    $mtime = microtime();
    $page = get_home();
    $mtime = explode(" ",$mtime);
    $mtime = $mtime[1] + $mtime[0];
    $endtime = $mtime;
    $totaltime = ($endtime - $starttime);
    memcache_set($memcache, 'homepage', $page, 0, 30);
    $page .= "\n<!-- Duly stored ($totaltime) -->";
}
else{
    $mtime = microtime();
    $mtime = explode(" ",$mtime);
    $mtime = $mtime[1] + $mtime[0];
    $endtime = $mtime;
    $totaltime = ($endtime - $starttime);
    $page .= "\n&lt;!-- served from memcache ($totaltime) -->";
}
die($page);

【讨论】:

    【解决方案4】:
        <?php
        //settings
        $cache_ext  = '.html'; //file extension
        $cache_time     = 3600;  //Cache file expires afere these seconds (1 hour = 3600 sec)
        $cache_folder   = 'cache/'; //folder to store Cache files
        $ignore_pages   = array('', '');
    
        $dynamic_url    = 'http://'.$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']; // requested dynamic page (full url)
        $cache_file     = $cache_folder.md5($dynamic_url).$cache_ext; // construct a cache file
        $ignore = (in_array($dynamic_url,$ignore_pages))?true:false; //check if url is in ignore list
    
        if (!$ignore && file_exists($cache_file) && time() - $cache_time < filemtime($cache_file)) { //check Cache exist and it's not expired.
            ob_start('ob_gzhandler'); //Turn on output buffering, "ob_gzhandler" for the compressed page with gzip.
            readfile($cache_file); //read Cache file
            echo '<!-- cached page - '.date('l jS \of F Y h:i:s A', filemtime($cache_file)).', Page : '.$dynamic_url.' -->';
            ob_end_flush(); //Flush and turn off output buffering
            exit(); //no need to proceed further, exit the flow.
        }
        //Turn on output buffering with gzip compression.
        ob_start('ob_gzhandler');
        ######## Your Website Content Starts Below #########
        ?>
        <!DOCTYPE html>
        <html>
            <head>
                <title>Page to Cache</title>
            </head>
                <body>
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut tellus libero.
                </body>
        </html>
        <?php
        ######## Your Website Content Ends here #########
    
        if (!is_dir($cache_folder)) { //create a new folder if we need to
            mkdir($cache_folder);
        }
        if(!$ignore){
            $fp = fopen($cache_file, 'w');  //open file for writing
            fwrite($fp, ob_get_contents()); //write contents of the output buffer in Cache file
            fclose($fp); //Close file pointer
        }
        ob_end_flush(); //Flush and turn off output buffering
    
        ?>
    

    【讨论】:

      【解决方案5】:

      在讨论缓存时经常被忽视的重要一点是进程同步以避免线程竞争(请参阅:https://en.wikipedia.org/wiki/Race_condition)。

      PHP 中没有同步的典型缓存场景是这样的:如果缓存中没有资源,或者资源过期,则必须创建它并放入缓存。碰巧遇到这种情况的第一个线程/进程正在尝试创建资源,在此期间,其他线程也将创建资源,从而导致线程竞争、缓存撞击和性能下降。

      问题被并发线程数和资源创建任务创建的工作负载放大。在繁忙的系统上,它可能会导致严重的问题。

      很少有 PHP 的缓存系统会考虑同步。

      其中之一是 php-no-slam-cache:https://github.com/tztztztz/php-no-slam-cache

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-24
        • 2011-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多