设为首页 收藏本站
查看: 537|回复: 0

[经验分享] PHP常见缓存技术分析(cache)

[复制链接]

尚未签到

发表于 2017-4-3 09:33:21 | 显示全部楼层 |阅读模式

在大部份情况下我们的网站都会使用数据库作为站点数据存储的容器。当你执行一个SQL查询时,典型的处理过程
是:连接数据库->准备SQL查询->发送查询到数据库->取得数据库返回结果->关闭数据库连接。但数据库中有些数据是完全静
态的或不太经常变动的,缓存系统会通过把SQL查询的结果缓存到一个更快的存储系统中存储,从而避免频繁操作数据库而很大程度上提高了程序执行时间,而且
缓存查询结果也允许你后期处理。



  普遍使用的缓
存技术




  数据缓存:这里所说的数据缓存是指数据库查询缓存,每次访问页面的时候,都会先检测相应的缓存数据是否存
在,如果不存在,就连接数据库,得到数据,并把查询结果序列化后保存到文件中,以后同样的查询结果就直接从缓存文件中获得。



  页面缓存:



  每次访问页面的时候,都会先检测相应的缓存页面文件是否存在,如果不存在,就连接数据库,得到数据,显示
页面并同时生成缓存页面文件,这样下次访问的时候页面文件就发挥作用了。(模板引擎和网上常见的一些缓存类通常有此功能)



  内存缓存:



  在里就不介绍了,不是本文所要讨论的,只简单提一下:



  Memcached是高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速
度。



  dbcached 是一款基于 Memcached 和 NMDB 的分布式 key-value
数据库内存缓存系统。



  以上的缓存技术虽然能很好的解决频繁查询数据库的问题,但其缺点在在于数据无时效性,下面我给出我在项目
中常用的方法:



  时间触发缓
存:




  检查文件是否存在并且时间戳小于设置的过期时间,如果文件修改的时间戳比当前时间戳减去过期时间戳大,那
么就用缓存,否则更新缓存。



  设定时间内不去判断数据是否要更新,过了设定时间再更新缓存。以上只适合对时效性要求不高的情况下使用
,否则请看下面。



  内容触发缓
存:




  当插入数据或更新数据时,强制更新缓存。



  在这里我们可以看到,当有大量数据频繁需要更新时,最后都要涉及磁盘读写操作。怎么解决呢?我在日常项目
中,通常并不缓存所有内容,而是缓存一部分不经常变的内容来解决。但在大负荷的情况下,最好要用共享内存做缓存系统。



  到这里PHP缓存也许有点解决方案了,但其缺点是,因为每次请求仍然要经过PHP解析,在大负荷的情况下
效率问题还是比效严重,在这种情况下,也许会用到静态缓存。



  静态缓存



  这里所说的静态缓存是指HTML缓存,HTML缓存一般是无需判断数据是否要更新的,因为通常在使用
HTML的场合一般是不经常变动内容的页面。数据更新的时候把HTML也强制更新一下就可以了。


  实例1:

<?php
/*
实    例:
include("cache.php");
$cache = new cache(30);
$cache->cacheCheck();
echo date("Y-m-d H:i:s");
$cache->caching();
*/
class cache {
// 缓存目录
var $cacheRoot        = "./cache/";
//缓存更新时间秒数,0为不缓存
var $cacheLimitTime   = 0;
//缓存文件名
var $cacheFileName    = "";
//缓存扩展名
var $cacheFileExt     = "php";
/*
* 构造函数
* int $cacheLimitTime 缓存更新时间
*/
function cache( $cacheLimitTime ) {
if( intval( $cacheLimitTime ) )
$this->cacheLimitTime = $cacheLimitTime;
$this->cacheFileName = $this->getCacheFileName();
ob_start();
}
/*
* 检查缓存文件是否在设置更新时间之内
* 返回:如果在更新时间之内则返回文件内容,反之则返回失败
*/
function cacheCheck(){
if( file_exists( $this->cacheFileName ) ) {
$cTime = $this->getFileCreateTime( $this->cacheFileName );
if( $cTime + $this->cacheLimitTime > time() ) {
echo file_get_contents( $this->cacheFileName );
ob_end_flush();
exit;
}
}
return false;
}
/*
* 缓存文件或者输出静态
* string $staticFileName 静态文件名(含相对路径)
*/
function caching( $staticFileName = "" ){
if( $this->cacheFileName ) {
$cacheContent = ob_get_contents();
//echo $cacheContent;
ob_end_flush();
if( $staticFileName ) {
$this->saveFile( $staticFileName, $cacheContent );
}
if( $this->cacheLimitTime )
$this->saveFile( $this->cacheFileName, $cacheContent );
}
}
/*
* 清除缓存文件
* string $fileName 指定文件名(含函数)或者all(全部)
* 返回:清除成功返回true,反之返回false
*/
function clearCache( $fileName = "all" ) {
if( $fileName != "all" ) {
$fileName = $this->cacheRoot . strtoupper(md5($fileName)).".".$this->cacheFileExt;
if( file_exists( $fileName ) ) {
return @unlink( $fileName );
}else return false;
}
if ( is_dir( $this->cacheRoot ) ) {
if ( $dir = @opendir( $this->cacheRoot ) ) {
while ( $file = @readdir( $dir ) ) {
$check = is_dir( $file );
if ( !$check )
@unlink( $this->cacheRoot . $file );
}
@closedir( $dir );
return true;
}else{
return false;
}
}else{
return false;
}
}
/*
* 根据当前动态文件生成缓存文件名
*/
function getCacheFileName() {
return  $this->cacheRoot . strtoupper(md5($_SERVER["REQUEST_URI"])).".".$this->cacheFileExt;
}
/*
* 缓存文件建立时间
* string $fileName   缓存文件名(含相对路径)
* 返回:文件生成时间秒数,文件不存在返回0
*/
function getFileCreateTime( $fileName ) {
if( ! trim($fileName) ) return 0;
if( file_exists( $fileName ) ) {
return intval(filemtime( $fileName ));
}else return 0;
}
/*
* 保存文件
* string $fileName  文件名(含相对路径)
* string $text      文件内容
* 返回:成功返回ture,失败返回false
*/
function saveFile($fileName, $text) {
if( ! $fileName || ! $text ) return false;
if( $this->makeDir( dirname( $fileName ) ) ) {
if( $fp = fopen( $fileName, "w" ) ) {
if( @fwrite( $fp, $text ) ) {
fclose($fp);
return true;
}else {
fclose($fp);
return false;
}
}
}
return false;
}
/*
* 连续建目录
* string $dir 目录字符串
* int $mode   权限数字
* 返回:顺利创建或者全部已建返回true,其它方式返回false
*/
function makeDir( $dir, $mode = "0777" ) {
if( ! $dir ) return 0;
$dir = str_replace( "\\", "/", $dir );
$mdir = "";
foreach( explode( "/", $dir ) as $val ) {
$mdir .= $val."/";
if( $val == ".." || $val == "." || trim( $val ) == "" ) continue;
if( ! file_exists( $mdir ) ) {
if(!@mkdir( $mdir, $mode )){
return false;
}
}
}
return true;
}
}

$cache = new cache(30);
$cache->cacheCheck();
echo date("Y-m-d H:i:s");
$cache->caching();
?>
   实例2: 数据缓存

<?php
class Cache {
private $dir = 'cache';
private $expiration = 3600;
function __construct($dir = '')
{
if(!empty($dir)){ $this->dir = $dir; }
}
private function _name($key)
{
return sprintf("%s/%s", $this->dir, sha1($key));
}
public function get($key, $expiration = '')
{
if ( !is_dir($this->dir) OR !is_writable($this->dir))
{
return FALSE;
}
$cache_path = $this->_name($key);
if (!@file_exists($cache_path))
{
return FALSE;
}
$expiration = empty($expiration) ? $this->expiration : $expiration;
if (filemtime($cache_path) < (time() - $expiration))
{
$this->clear($key);
return FALSE;
}
if (!$fp = @fopen($cache_path, 'rb'))
{
return FALSE;
}
flock($fp, LOCK_SH);
$cache = '';
if (filesize($cache_path) > 0)
{
$cache = unserialize(fread($fp, filesize($cache_path)));
}
else
{
$cache = NULL;
}
flock($fp, LOCK_UN);
fclose($fp);
return $cache;
}
public function set($key, $data)
{
if ( !is_dir($this->dir) OR !is_writable($this->dir))
{
$this->_makeDir($this->dir);
}
$cache_path = $this->_name($key);
if ( ! $fp = fopen($cache_path, 'wb'))
{
return FALSE;
}
if (flock($fp, LOCK_EX))
{
fwrite($fp, serialize($data));
flock($fp, LOCK_UN);
}
else
{
return FALSE;
}
fclose($fp);
@chmod($cache_path, 0777);
return TRUE;
}
public function clear($key)
{
$cache_path = $this->_name($key);
if (file_exists($cache_path))
{
unlink($cache_path);
return TRUE;
}
return FALSE;
}
public function clearAll()
{
$dir = $this->dir;
if (is_dir($dir))
{
$dh=opendir($dir);
while (false !== ( $file = readdir ($dh)))
{
if($file!="." && $file!="..")
{
$fullpath=$dir."/".$file;
if(!is_dir($fullpath)) {
unlink($fullpath);
} else {
delfile($fullpath);
}
}
}
closedir($dh);
// rmdir($dir);
}
}
private function _makeDir( $dir, $mode = "0777" ) {
if( ! $dir ) return 0;
$dir = str_replace( "\\", "/", $dir );
$mdir = "";
foreach( explode( "/", $dir ) as $val ) {
$mdir .= $val."/";
if( $val == ".." || $val == "." || trim( $val ) == "" ) continue;
if( ! file_exists( $mdir ) ) {
if(!@mkdir( $mdir, $mode )){
return false;
}
}
}
return true;
}
}

   例子:

<?
require_once('cache.php');
$cache = new Cache();
$data = $cache->get('key');
if ($data === FALSE)
{
$data = 'This will be cached';
$cache->set('key', $data);
echo $data.'--first time';
}
echo $data;
//$cache->clearAll();
//$cache->clear('key');
//Do something with $data

   另一个数据缓存:

<?php
class file_cache
{
private $root_dir;
public function __construct ($root_dir)
{
$this->root_dir = $root_dir;
if (FALSE == file_exists($this->root_dir))
{
mkdir($this->root_dir, 0700, true);
}
}
public function set ($key, $value)
{
$key = $this->escape_key($key);
$file_name = $this->root_dir . '/' . $key;
$dir = dirname($file_name);
if (FALSE == file_exists($dir))
{
mkdir($dir, 0700, true);
}
file_put_contents($file_name, serialize($value), LOCK_EX);
}
public function get ($key)
{
$key = $this->escape_key($key);
$file_name = $this->root_dir . '/' . $key;
if (file_exists($file_name))
{
return unserialize(file_get_contents($file_name));
}
return null;
}
public function remove ($key)
{
$key = $this->escape_key($key);
$file = $this->root_dir . '/' . $key;
if (file_exists($file))
{
unlink($file);
}
}
public function remove_by_search ($key)
{
$key = $this->escape_key($key);
$dir = $this->root_dir . '/' . $key;
if (strrpos($key, '/') < 0)
$key .= '/';
if (file_exists($dir))
{
$this->removeDir($dir);
}
}
private function escape_key ($key)
{
return str_replace('..', '', $key);
}
function removeDir($dirName)
{
$result = false;
$handle = opendir($dirName);
while(($file = readdir($handle)) !== false)
{
if($file != '.' && $file != '..')
{
$dir = $dirName . DIRECTORY_SEPARATOR . $file;
is_dir($dir) ? $this->removeDir($dir) : unlink($dir);
}
}
closedir($handle);
rmdir($dirName) ? true : false;
return $result;
}
}

$data_1 = array(
'u_id' => 1,
'name' => '利沙'
);
$data_2 = array(
'u_id' => 2,
'name' => 'WaWa'
);
$cache = new file_cache("test");
$cache->set("user/1/data", $data_1);  //保存数据
$cache->set("user/2/data", $data_2);  //保存数据
$result = $cache->get("user/1/data"); //获取数据
echo '测试如下:<pre>';
print_r($result);
//$cache->remove("user/1/data"); //删除数据
//$cache->remove_by_search("user", $data_1);  //删除user节点下所有数据

   附两个较好的其他缓存类

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-359420-1-1.html 上篇帖子: PHP Memcached + APC + 文件缓存封装 下篇帖子: JS中encodeURIComponent函数用php解码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表