标签归档:缓存

PHP框架Phalcon 之 使用缓存

Phalcon Cache
Phalcon提供的后端缓存看起来已经很多了,不过你需要的那个可能还是没有在这个列表里面。从https://github.com/phalcon/incubator中,你可以找到:

Phalcon\Cache\Backend\Database
Phalcon\Cache\Backend\Redis
Phalcon\Cache\Backend\Wincache

Phalcon\Cache\Multiple提供了设置多个后端的功能,写时同时写入。

每个后端都需要提供一个前端,这个前端主要负责数据如何输入,以什么格式保存,数据读出后以什么方法处理等。Phalcon\Cache\Frontend\Output和Phalcon\Cache\Frontend\Data的主要区别是数据的读入,前者把PHP的标准输出当做输入(通过使用PHP的输出缓冲实现),后者可以应用任何数据,保存和取出时分别进行序列化和反序列化处理,如果不希望采用这种处理,可以使用更加具体的前端,比如Phalcon\Cache\Frontend\Base64,会进行base64之后存储,如果希望不做任何处理可以使用Phalcon\Cache\Frontend\None。

使用如下程序测试:

public function memAction(){
	// Cache data for 2 days
	/*
	$frontCache = new \Phalcon\Cache\Frontend\Data(array(
    		"lifetime" => 172800
 	));
	*/

 	$frontCache = new \Phalcon\Cache\Frontend\Json(array(
    		"lifetime" => 172800
 	));

 	//Create the Cache setting memcached connection options
 	$cache = new \Phalcon\Cache\Backend\Libmemcached($frontCache, array(
     		'servers' => array(
         		array('host' => '127.0.0.1',
               		'port' => 11211,
               		'weight' => 1),
     		),
     		'client' => array(
        		\Memcached::OPT_HASH => \Memcached::HASH_MD5,
        		\Memcached::OPT_PREFIX_KEY => 'prefix.',
     		)
 	));

 	//Cache arbitrary data
 	$cache->save('my-cache-data', array(1, 2, 3, 4,array("111","222","333")));

 	//Get data
 	$data = $cache->get('my-cache-data');
	print_r($data);

	$this->view->disable();
}

首先使用\Phalcon\Cache\Frontend\Data()作为前端保存数据,查看保存的数据为:
Phalcon Cache
这个就是数据序列化存储的结果。

改为\Phalcon\Cache\Frontend\Json()作为前端,查看保存的数据为:
Phalcon Cache
这是JSON数据。

所以,当你要以一种自定义的格式把数据保存到后端时,你就需要自己实现一个前端。

另外,注意到一个稍微特殊的前端\Phalcon\Cache\Frontend\Output,它把PHP的标准输出作为它的输入,我们知道,后端的save()方法在没有指定内容时,它就像前端索要内容,这个用在需要输出内容同时又要把这些输出内容进行缓存的情况,它可以同时完成这个操作:

<?php

 //Create an Output frontend. Cache the files for 2 days
 $frontCache = new Phalcon\Cache\Frontend\Output(array(
   "lifetime" => 172800
 ));

 // Create the component that will cache from the "Output" to a "File" backend
 // Set the cache file directory - it's important to keep the "/" at the end of
 // the value for the folder
 $cache = new Phalcon\Cache\Backend\File($frontCache, array(
     "cacheDir" => "../app/cache/"
 ));

 // Get/Set the cache file to ../app/cache/my-cache.html
 $content = $cache->start("my-cache.html");

 // If $content is null then the content will be generated for the cache
 if ($content === null) {

     //Print date and time
     echo date("r");

     //Generate a link to the sign-up action
     echo Phalcon\Tag::linkTo(
         array(
             "user/signup",
             "Sign Up",
             "class" => "signup-button"
         )
     );

     // Store the output into the cache file
     $cache->save();

 } else {

     // Echo the cached output
     echo $content;
 }

接下来分析一段源代码加深对Phalcon缓存实现的理解(https://github.com/phalcon/incubator/blob/master/Library/Phalcon/Cache/Backend/Database.php),对一个后端而言,最主要的是get()和save()方法:

    public function get($keyName, $lifetime = null)
    {
        $prefixedKey = $this->getPrefixedIdentifier($keyName);
        $options     = $this->getOptions();
        $sql         = "SELECT data, lifetime FROM " . $options['table'] . " WHERE key_name = ?";
        $cache       = $options['db']->fetchOne($sql, Db::FETCH_ASSOC, array($prefixedKey));
		//不存在返回null
        if (!$cache) {
            return null;
        }
		//获取前端
        $frontend = $this->getFrontend();
		//没有指定$lifetime则默认使用前端的设置
        if ($lifetime === null) {
            $lifetime = $frontend->getLifetime();
        }

        //缓存过期删除
        if ($cache['lifetime'] < (time() - $lifetime)) {
            $options['db']->execute("DELETE FROM " . $options['table'] . " WHERE key_name = ?", array($prefixedKey));

            return null;
        }

        $this->setLastKey($keyName);
		//调用前端的afterRetrieve方法,通过它实现了不同前端的不同处理方法
        return $frontend->afterRetrieve($cache['data']);
}
	
	//保存缓存
public function save($keyName = null, $content = null, $lifetime = null, $stopBuffer = true)
{
	//确定缓存的key
        if ($keyName === null) {
            $lastKey = $this->_lastKey;
        } else {
            $lastKey = $keyName;
        }

        if (!$lastKey) {
            throw new Exception('The cache must be started first');
        }

        $options = $this->getOptions();
        $frontend = $this->getFrontend();

		//没有指定缓存则从前端获取
        if ($content === null) {
            $content = $frontend->getContent();
        }

        //检查缓存是否存在
        $prefixedKey = $this->getPrefixedIdentifier($keyName);
        $sql         = "SELECT data, lifetime FROM " . $options['table'] . " WHERE key_name = ?";
        $cache       = $options['db']->fetchOne($sql, Db::FETCH_ASSOC, array($prefixedKey));
		
		//缓存不存储则插入,存在则更新
        if (!$cache) {
            $options['db']->execute("INSERT INTO " . $options['table'] . " VALUES (?, ?, ?)", array(
                $prefixedKey,
				//保存内容前先调用前端的beforeStore方法处理数据
                $frontend->beforeStore($content),
                time()
            ));
        } else {
            $options['db']->execute(
                "UPDATE " . $options['table'] . " SET data = ?, lifetime = ? WHERE key_name = ?",
                array(
                    $frontend->beforeStore($content),
                    time(),
                    $prefixedKey
                )
            );
        }

        // Stop the buffer, this only applies for Phalcon\Cache\Frontend\Output
        if ($stopBuffer) {
            $frontend->stop();
        }

        // Print the buffer, this only applies for Phalcon\Cache\Frontend\Output
        if ($frontend->isBuffering()) {
            echo $content;
        }

        $this->_started = false;
    }

以上程序可知get()缓存时,并没有修改它的时间戳,实际传递进去的缓存时间只是判断缓存是否过期的参数(所有后端都应该是如此实现),在save()时缓存的时间戳被更新。

————————————————————————–
安装使用Memcached:

##安装libmemcached库
#wget https://launchpadlibrarian.net/165454254/libmemcached-1.0.18.tar.gz
#tar zxvf libmemcached-1.0.18.tar.gz
#cd libmemcached-1.0.18
#./configure --prefix=/usr/local/libmemcached --with-memcached
#make
#make install

##安装针对libmemcached库的PHP扩展memcached
#wget http://pecl.php.net/get/memcached-2.2.0.tgz
#tar zxvf memcached-2.2.0.tgz
#cd memcached-2.2.0
#/usr/local/php/bin/phpize
#./configure --with-php-config=/usr/local/php/bin/php-config --with-libmemcached-dir=/usr/local/libmemcached
#make
#make install

##往php.ini中添加
extension= memcached.so

##安装memcached服务器依赖的工具livevent
#wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
#tar zxvf libevent-2.0.21-stable.tar.gz
#cd libevent-2.0.21-stable
#./configure --prefix=/usr
#make
#make install

##安装memcached服务器
#wget http://memcached.org/latest
#tar -zxvf memcached-1.x.x.tar.gz
#cd memcached-1.x.x
#./configure --prefix=/usr/local/memcached --with-libevent=/usr
#make
#make install

##启动memcached服务器
memcached -d -p 11211 -u root -m 64 -c 10240

———————————————————
以下官方文档内容:

使用缓存提高性能(Improving Performance with Cache)

Phalcon provides the Phalcon\Cache class allowing faster access to frequently used or already processed data. Phalcon\Cache is written in C, achieving higher performance and reducing the overhead when getting items from the backends. This class uses an internal structure of frontend and backend components. Front-end components act as input sources or interfaces, while backend components offer storage options to the class.
Phalcon提供Phalcon\Cache类允许快速访问经常使用或已经处理的数据。Phalcon\Cache用C编写,实现从后端获取东西时的更高性能和降低开销。这类使用一个内部结构的前端和后端组件。前端组件作为输入源或接口,而后端组件提供存储选项。

什么情况下使用缓存?(When to implement cache?)
Although this component is very fast, implementing it in cases that are not needed could lead to a loss of performance rather than gain. We recommend you check this cases before using a cache:
You are making complex calculations that every time return the same result (changing infrequently)
You are using a lot of helpers and the output generated is almost always the same
You are accessing database data constantly and these data rarely change

NOTE Even after implementing the cache, you should check the hit ratio of your cache over a period of time. This can easily be done, especially in the case of Memcache or Apc, with the relevant tools that backends provide.

缓存行为(Caching Behavior)
The caching process is divided into 2 parts:
缓存过程分隔为两个部分:
Frontend: This part is responsible for checking if a key has expired and perform additional transformations to the data before storing and after retrieving them from the backend-
前端:这个部分代表检查一个key是否已经过期和执行在从后端存储之前和取出它们之后的其它的数据转换
Backend: This part is responsible for communicating, writing/reading the data required by the frontend.

缓存输出片段(Caching Output Fragments)
An output fragment is a piece of HTML or text that is cached as is and returned as is. The output is automatically captured from the ob_* functions or the PHP output so that it can be saved in the cache. The following example demonstrates such usage. It receives the output generated by PHP and stores it into a file. The contents of the file are refreshed every 172800 seconds (2 days).
一个输出片段是一个块HTML或文本。输出自动使用ob_*函数采集或PHP输出以致它可以在缓存中保存。

The implementation of this caching mechanism allows us to gain performance by not executing the helper Phalcon\Tag::linkTo call whenever this piece of code is called.

<?php

//Create an Output frontend. Cache the files for 2 days
$frontCache = new Phalcon\Cache\Frontend\Output(array(
    "lifetime" => 172800
));

// Create the component that will cache from the "Output" to a "File" backend
// Set the cache file directory - it's important to keep the "/" at the end of
// the value for the folder
$cache = new Phalcon\Cache\Backend\File($frontCache, array(
    "cacheDir" => "../app/cache/"
));

// Get/Set the cache file to ../app/cache/my-cache.html
$content = $cache->start("my-cache.html");

// If $content is null then the content will be generated for the cache
if ($content === null) {

    //Print date and time
    echo date("r");

    //Generate a link to the sign-up action
    echo Phalcon\Tag::linkTo(
        array(
            "user/signup",
            "Sign Up",
            "class" => "signup-button"
        )
    );

    // Store the output into the cache file
    $cache->save();

} else {

    // Echo the cached output
    echo $content;
}

NOTE In the example above, our code remains the same, echoing output to the user as it has been doing before. Our cache component transparently captures that output and stores it in the cache file (when the cache is generated) or it sends it back to the user pre-compiled from a previous call, thus avoiding expensive operations.

缓存任意数据(Caching Arbitrary Data)
Caching just data is equally important for your application. Caching can reduce database load by reusing commonly used (but not updated) data, thus speeding up your application.(说缓存可以提高性能)
文件后端存储器例子(File Backend Example)
One of the caching adapters is ‘File’. The only key area for this adapter is the location of where the cache files will be stored. This is controlled by the cacheDir option which must have a backslash at the end of it.(指定缓存的目录路基后面需要有斜杠)

<?php

// Cache the files for 2 days using a Data frontend
$frontCache = new Phalcon\Cache\Frontend\Data(array(
    "lifetime" => 172800
));

// Create the component that will cache "Data" to a "File" backend
// Set the cache file directory - important to keep the "/" at the end of
// of the value for the folder
$cache = new Phalcon\Cache\Backend\File($frontCache, array(
    "cacheDir" => "../app/cache/"
));

// Try to get cached records
$cacheKey = 'robots_order_id.cache';
$robots    = $cache->get($cacheKey);
if ($robots === null) {

    // $robots is null because of cache expiration or data does not exist
    // Make the database call and populate the variable
    $robots = Robots::find(array("order" => "id"));

    // Store it in the cache
    $cache->save($cacheKey, $robots);
}

// Use $robots 🙂
foreach ($robots as $robot) {
   echo $robot->name, "\n";
}

Memcached 后端存储器例子(Memcached Backend Example)
The above example changes slightly (especially in terms of configuration) when we are using a Memcached backend.

<?php

//Cache data for one hour
$frontCache = new Phalcon\Cache\Frontend\Data(array(
    "lifetime" => 3600
));

// Create the component that will cache "Data" to a "Memcached" backend
// Memcached connection settings
$cache = new Phalcon\Cache\Backend\Libmemcached($frontCache, array(
    "servers" => array(
            array(
                    "host" => "127.0.0.1",
                    "port" => "11211",
                    "weight" => "1"
            )
    )
));

// Try to get cached records
$cacheKey = 'robots_order_id.cache';
$robots    = $cache->get($cacheKey);
if ($robots === null) {

    // $robots is null because of cache expiration or data does not exist
    // Make the database call and populate the variable
    $robots = Robots::find(array("order" => "id"));

    // Store it in the cache
    $cache->save($cacheKey, $robots);
}

// Use $robots 🙂
foreach ($robots as $robot) {
   echo $robot->name, "\n";
}

查询缓存(Querying the cache)
The elements added to the cache are uniquely identified by a key. In the case of the File backend, the key is the actual filename. To retrieve data from the cache, we just have to call it using the unique key. If the key does not exist, the get method will return null.
添加到缓存中的元素有一个唯一的key。对文件后端它就是文件名。要从缓存获取数据,我们只要使用这个唯一key调用get方法。如果key不存在,get方法返回null。

<?php

// Retrieve products by key "myProducts"
$products = $cache->get("myProducts");

If you want to know which keys are stored in the cache you could call the queryKeys method:

<?php

// Query all keys used in the cache
$keys = $cache->queryKeys();
foreach ($keys as $key) {
    $data = $cache->get($key);
    echo "Key=", $key, " Data=", $data;
}

//Query keys in the cache that begins with "my-prefix"
$keys = $cache->queryKeys("my-prefix");

删除缓存数据(Deleting data from the cache)
There are times where you will need to forcibly invalidate a cache entry (due to an update in the cached data). The only requirement is to know the key that the data have been stored with.

<?php

// Delete an item with a specific key
$cache->delete("someKey");

// Delete all items from the cache
$keys = $cache->queryKeys();
foreach ($keys as $key) {
    $cache->delete($key);
}

检查缓存是否存在(Checking cache existence)It is possible to check if a cache already exists with a given key:

<?php

if ($cache->exists("someKey")) {
    echo $cache->get("someKey");
} else {
    echo "Cache does not exists!";
}

有效期(Lifetime)
A “lifetime” is a time in seconds that a cache could live without expire. By default, all the created caches use the lifetime set in the frontend creation. You can set a specific lifetime in the creation or retrieving of the data from the cache:

Setting the lifetime when retrieving:

<?php

$cacheKey = 'my.cache';

//Setting the cache when getting a result
$robots = $cache->get($cacheKey, 3600);
if ($robots === null) {

    $robots = "some robots";

    // Store it in the cache
    $cache->save($cacheKey, $robots);
}

Setting the lifetime when saving:

<?php

$cacheKey = 'my.cache';

$robots = $cache->get($cacheKey);
if ($robots === null) {

    $robots = "some robots";

    //Setting the cache when saving data
    $cache->save($cacheKey, $robots, 3600);
}

多级缓存(Multi-Level Cache)
This feature ​of the cache component, ​allows ​the developer to implement a multi-level cache​. This new feature is very ​useful because you can save the same data in several cache​ locations​ with different lifetimes, reading ​first from the one with the faster adapter and ending with the slowest one until the data expire​s​:

<?php

use Phalcon\Cache\Frontend\Data as DataFrontend,
    Phalcon\Cache\Multiple,
    Phalcon\Cache\Backend\Apc as ApcCache,
    Phalcon\Cache\Backend\Memcache as MemcacheCache,
    Phalcon\Cache\Backend\File as FileCache;

$ultraFastFrontend = new DataFrontend(array(
    "lifetime" => 3600
));

$fastFrontend = new DataFrontend(array(
    "lifetime" => 86400
));

$slowFrontend = new DataFrontend(array(
    "lifetime" => 604800
));

//Backends are registered from the fastest to the slower
$cache = new Multiple(array(
    new ApcCache($ultraFastFrontend, array(
        "prefix" => 'cache',
    )),
    new MemcacheCache($fastFrontend, array(
        "prefix" => 'cache',
        "host" => "localhost",
        "port" => "11211"
    )),
    new FileCache($slowFrontend, array(
        "prefix" => 'cache',
        "cacheDir" => "../app/cache/"
    ))
));

//Save, saves in every backend
$cache->save('my-key', $data);

前端适配器(Frontend Adapters)
The available frontend adapters that are used as interfaces or input sources to the cache are:

Adapter Description Example
Output Read input data from standard PHP output Phalcon\Cache\Frontend\Output
Data It’s used to cache any kind of PHP data (big arrays, objects, text, etc). Data is serialized before stored in the backend. Phalcon\Cache\Frontend\Data
Base64 It’s used to cache binary data. The data is serialized using base64_encode before be stored in the backend. Phalcon\Cache\Frontend\Base64
Json Data is encoded in JSON before be stored in the backend. Decoded after be retrieved. This frontend is useful to share data with other languages or frameworks. Phalcon\Cache\Frontend\Json
IgBinary It’s used to cache any kind of PHP data (big arrays, objects, text, etc). Data is serialized using IgBinary before be stored in the backend. Phalcon\Cache\Frontend\Igbinary
None It’s used to cache any kind of PHP data without serializing them. Phalcon\Cache\Frontend\None

Adapter Description Example
Output Read input data from standard PHP output Phalcon\Cache\Frontend\Output
Data It’s used to cache any kind of PHP data (big arrays, objects, text, etc). Data is serialized before stored in the backend. Phalcon\Cache\Frontend\Data
Base64 It’s used to cache binary data. The data is serialized using base64_encode before be stored in the backend. Phalcon\Cache\Frontend\Base64
Json Data is encoded in JSON before be stored in the backend. Decoded after be retrieved. This frontend is useful to share data with other languages or frameworks. Phalcon\Cache\Frontend\Json
IgBinary It’s used to cache any kind of PHP data (big arrays, objects, text, etc). Data is serialized using IgBinary before be stored in the backend. Phalcon\Cache\Frontend\Igbinary
None It’s used to cache any kind of PHP data without serializing them. Phalcon\Cache\Frontend\None

自定义前端适配器(Implementing your own Frontend adapters)
The Phalcon\Cache\FrontendInterface interface must be implemented in order to create your own frontend adapters or extend the existing ones.

后端适配器(Backend Adapters)
The backend adapters available to store cache data are:

Adapter Description Info Required Extensions Example
File Stores data to local plain files     Phalcon\Cache\Backend\File
Memcached Stores data to a memcached server Memcached memcache Phalcon\Cache\Backend\Memcache
APC Stores data to the Alternative PHP Cache (APC) APC APC extension Phalcon\Cache\Backend\Apc
Mongo Stores data to Mongo Database MongoDb Mongo Phalcon\Cache\Backend\Mongo
XCache Stores data in XCache XCache xcache extension Phalcon\Cache\Backend\Xcache

PHP框架Phalcon 之 在ORM中缓存

Caching in the ORM 在ORM中缓存
Every application is different, we could have models whose data change frequently and others that rarely change. Accessing database systems is often one of the most common bottlenecks in terms of performance. This is due to the complex connection/communication processes that PHP must do in each request to obtain data from the database. Therefore, if we want to achieve good performance we need to add some layers of caching where the application requires it.
不经常改变的数据要缓存起来…

This chapter explains the possible points where it is possible to implement caching to improve performance. The framework gives you the tools to implement the cache where you demand of it according to the architecture of your application.
说它提供了缓存。

Caching Resultsets 缓存结果集
A well established technique to avoid the continuous access to the database is to cache resultsets that don’t change frequently using a system with faster access (usually memory).
把不经常改变的结果集缓存起来。

When Phalcon\Mvc\Model requires a service to cache resultsets, it will request it to the Dependency Injector Container with the convention name “modelsCache”.
当Phalcon\Mvc\Model要去缓存结果集,它会通过DI容器获取“modelsCache”(这个是缓存对象,复杂读取写入缓存)。

As Phalcon provides a component to cache any kind of data, we’ll explain how to integrate整合 it with Models. First, you must register it as a service in the services container:
首先要在容器中注册:

<?php

//Set the models cache service
$di->set('modelsCache', function() {

    //Cache data for one day by default
    $frontCache = new \Phalcon\Cache\Frontend\Data(array(
        "lifetime" => 86400
    ));

    //Memcached connection settings
    $cache = new \Phalcon\Cache\Backend\Memcache($frontCache, array(
        "host" => "localhost",
        "port" => "11211"
    ));

    return $cache;
});

You have complete control in creating and customizing the cache before being used by registering the service as an anonymous function. Once the cache setup is properly defined you could cache resultsets as follows:
可以通过匿名函数完全控制缓存对象的创建和定制。如下缓存结果集:

<?php

// Get products without caching
$products = Products::find();

// Just cache the resultset. The cache will expire in 1 hour (3600 seconds)
$products = Products::find(array(
    "cache" => array("key" => "my-cache")
));

// Cache the resultset for only for 5 minutes
$products = Products::find(array(
    "cache" => array("key" => "my-cache", "lifetime" => 300)
));

// Using a custom cache(取回缓存的方法)
$products = Products::find(array("cache" => $myCache));

Caching could be also applied to resultsets generated using relationships:
缓存也可以应用到由关系产生的结果集

<?php

// Query some post
$post = Post::findFirst();

// Get comments related to a post, also cache it
$comments = $post->getComments(array(
    "cache" => array("key" => "my-key")
));

// Get comments related to a post, setting lifetime
$comments = $post->getComments(array(
    "cache" => array("key" => "my-key", "lifetime" => 3600)
));

When a cached resultset needs to be invalidated, you can simply delete it from the cache using the previously specified key.
缓存无效,可以通过指定的key删除。

Note that not all resultsets must be cached. Results that change very frequently should not be cached since they are invalidated very quickly and caching in that case impacts performance. Additionally, large datasets that do not change frequently could be cached, but that is a decision that the developer has to make based on the available caching mechanism and whether the performance impact to simply retrieve that data in the first place is acceptable.(一段废话)

Overriding find/findFirst 重写find/findFirst
As seen above, these methods are available in models that inherit Phalcon\Mvc\Model:

<?php

class Robots extends Phalcon\Mvc\Model
{

    public static function find($parameters=null)
    {
        return parent::find($parameters);
    }

    public static function findFirst($parameters=null)
    {
        return parent::findFirst($parameters);
    }

}

By doing this, you’re intercepting all the calls to these methods, this way, you can add a cache layer or run the query if there is no cache. For example, a very basic cache implementation, uses a static property to avoid that a record would be queried several times in a same request:
重写这两个方法,添加缓存层:

<?php

class Robots extends Phalcon\Mvc\Model
{

    protected static $_cache = array();

    /**
     * Implement a method that returns a string key based
     * on the query parameters
     */
    protected static function _createKey($parameters)
    {
        $uniqueKey = array();
        foreach ($parameters as $key => $value) {
            if (is_scalar($value)) {
                $uniqueKey[] = $key . ':' . $value;
            } else {
                if (is_array($value)) {
                    $uniqueKey[] = $key . ':[' . self::_createKey($value) .']';
                }
            }
        }
        return join(',', $uniqueKey);
    }

    public static function find($parameters=null)
    {

        //Create an unique key based on the parameters
        $key = self::_createKey($parameters);

        if (!isset(self::$_cache[$key])) {
            //Store the result in the memory cache
            self::$_cache[$key] = parent::find($parameters);
        }

        //Return the result in the cache
        return self::$_cache[$key];
    }

    public static function findFirst($parameters=null)
    {
        // ...
    }

}

Access the database is several times slower than calculate a cache key, you’re free in implement the key generation strategy you find better for your needs. Note that a good key avoids collisions as much as possible, this means that different keys returns unrelated records to the find parameters.

In the above example, we used a cache in memory, it is useful as a first level cache. Once we have the memory cache, we can implement a second level cache layer like APC/XCache or a NoSQL database:
实现第二层次缓存:

<?php

public static function find($parameters=null)
{

    //Create an unique key based on the parameters
    $key = self::_createKey($parameters);

    if (!isset(self::$_cache[$key])) {

        //We're using APC as second cache
        if (apc_exists($key)) {

            $data = apc_fetch($key);

            //Store the result in the memory cache
            self::$_cache[$key] = $data;

            return $data;
        }

        //There are no memory or apc cache
        $data = parent::find($parameters);

        //Store the result in the memory cache
        self::$_cache[$key] = $data;

        //Store the result in APC
        apc_store($key, $data);

        return $data;
    }

    //Return the result in the cache
    return self::$_cache[$key];
}

This gives you full control on how the the caches must be implemented for each model, if this strategy is common to several models you can create a base class for all of them:
建立一个公共模型,然后让其它模型继承它,那么就可以使用自定义的缓存策略。

<?php

class CacheableModel extends Phalcon\Mvc\Model
{

    protected static function _createKey($parameters)
    {
        // .. create a cache key based on the parameters
    }

    public static function find($parameters=null)
    {
        //.. custom caching strategy
    }

    public static function findFirst($parameters=null)
    {
        //.. custom caching strategy
    }
}

Then use this class as base class for each ‘Cacheable’ model:

<?php

class Robots extends CacheableModel
{

}

Forcing Cache
这个内容跟以上内容重复。

Caching PHQL Queries PHQL查询缓存
All queries in the ORM, no matter how high level syntax we used to create them are handled internally using PHQL. This language gives you much more freedom to create all kinds of queries. Of course these queries can be cached:
内部都使用PHQL,这种查询可以被缓存:(PHQL先装换成IR,这里就是缓存这个IR)

<?php

$phql = "SELECT * FROM Cars WHERE name = :name:";

$query = $this->modelsManager->createQuery($phql);

$query->cache(array(
    "key" => "cars-by-name",
    "lifetime" => 300
));

$cars = $query->execute(array(
    'name' => 'Audi'
));

(注意,缓存对象务必要在DI中先注册)

If you don’t want to use the implicit cache just save the resulset into your favorite cache backend:

<?php

$phql = "SELECT * FROM Cars WHERE name = :name:";

$cars = $this->modelsManager->executeQuery($phql, array(
    'name' => 'Audi'
));

apc_store('my-cars', $cars);

Reusable Related Records
Caching Related Records
Caching Related Records Recursively
Caching based on Conditions
Caching of PHQL planning

Zen-cart中的数据库查询结果缓存

Zen-cart中提供了对数据库查询结果进行缓存功能。数据库查询结果缓存原理非常简单,对查询的SQL语句取散列值,然后把查询返回的结果关联这个散列值保存起来,当有同样的查询时就从保存的结果中直接返回(前提是没有过期)。

首先看缓存类的框架:

class cache extends base {
  //判断缓存是否存在,$zf_cachetime用来指定缓存时间,对应过期的缓存当然不能判断为存在
  function sql_cache_exists($zf_query, $zf_cachetime) {
    global $db;
    $zp_cache_name = $this->cache_generate_cache_name($zf_query);
    switch (SQL_CACHE_METHOD) {
      case 'file':
      //................
      break;
      case 'database':
      //................
      break;
      case 'memory':
      return false;
      break;
      case 'none':
      default:
      return false;
      break;
    }
  }
  //判断缓存是否过期
  function sql_cache_is_expired($zf_query, $zf_cachetime) {
  }
  //马上过期
  function sql_cache_expire_now($zf_query) {
  }
  //保存缓存
  function sql_cache_store($zf_query, $zf_result_array) {
  }
  //读取缓存
  function sql_cache_read($zf_query) {
  }
  //刷新缓存
  function sql_cache_flush_cache() {
  }
  //生成缓存名
  function cache_generate_cache_name($zf_query) {
  }
}

从源代码可以看出,Zen-cart只支持把缓存保存到file和database中,保存到database中是比较少用的,在高并发的情况下,更加倾向把结果保存到memory中,不过Zen-cart没有提供实现(可做二次开发)。

另外,保存的方式使用常量SQL_CACHE_METHOD指定,这个值需要在配置文件中指定:

#includes/configure.php
define('SQL_CACHE_METHOD', 'file'); 
define('DIR_FS_SQL_CACHE', 'D:/www/web/z151.com/public_html/cache');

如果SQL_CACHE_METHOD为none,那么根本不会进行缓存。
注:SQL_CACHE_METHOD在安装Zen-cart时就会提示把缓存的的方法,是file还是database,默认是none。

缓存对象的生成是在环境初始化时进行的:

$autoLoadConfig[30][] = array('autoType'=>'classInstantiate',
                                'className'=>'cache',
                                'objectName'=>'zc_cache');

这个对象的名字叫zc_cache,它是环境初始化中首先构建的对象之一(在它之前是数据库初始化)。

那么这个对象何时会用到?实际上就是在触发SELECT查询时这个对象就会被使用。

##includes/clssses/db/mysql/query_factory.php

class queryFactory extends base {
  function Execute($zf_sql, $zf_limit = false, $zf_cache = false, $zf_cachetime=0) {
    //....
    global $zc_cache;
  }
}

Execute方法是Zen-cart中对数据库操作封装最核心的方法,zf_sql是要执行的SQL(不仅限于查询),zf_limit限制返回的结果数量,zf_cache表示是否缓存查询结果(只对SELECT查询起作用),zf_cachetime指定缓存时间。

目前Zen-cart默认代码应用查询缓存的有如下地方:

##includes/classes/category_tree.php
//...
$categories = $db->Execute($categories_query, '', true, 150);
//...

另一个地方是读取配置文件:

##includes/init_includes/init_db_config_read.php
$use_cache = (isset($_GET['nocache']) ? false : true ) ;
$configuration = $db->Execute('select configuration_key as cfgkey, configuration_value as cfgvalue
                                 from ' . TABLE_CONFIGURATION, '', $use_cache, 150);

这两个地方读取的数据都是经常不改变的,所以缓存起来有必要。特别是配置表,如果每次都查询数据库,并发量一大,就会耗费大量的数据库资源,而这些消耗是完全没有必要的。

另外,虽然Zen-cart中的cache类是用来缓存数据库查询结果的,但是并不意味着你只能用它来缓存数据库查询结果,你完成可以把某个变量缓存起来,比如某个变量每次请求时都要重新构建,而已内容都是一样的,这种情况就非常合适缓存,只是你需要使用这个变量之前首先要判断缓存是否存在,这个操作控制起来非常简单。

举例:

$cs = $db->Execute("select * from countries");
while(!$cs->EOF){
  echo $cs->fields['country_name']."<br />";
  $cs->MoveNext();
}

使用压力测试工具对这对代码进行测试,获取结果。

然后对带数据缓存的版本进行测试:

$cs = $db->Execute("select * from countries",0,true,2000);
while(!$cs->EOF){
  echo $cs->fields['country_name']."<br />";
  $cs->MoveNext();
}

对比结果就能得出结论。

在高并发环境中,对于频繁访问的数据,如果能对数据进行缓存,那么数据库的压力下减是非常明显的。如果并发量很小,几乎感觉不到缓存有什么作用。

永久链接:http://blog.ifeeline.com/806.html

Magento缓存与全局配置文件缓存

使用如下例子:
1 先关闭缓存
然后在任何一个控制器中添加一个方法加入如下代码:

$xml = Mage::getConfig()->getNode()->asXml();
file_put_contents('D:/config_file.xml', $xml);

在我这里,产生的文件大小为684K。这是一个非常让我吃惊的数字。如果每个请求都重复这个过程,如果100个同时请求,将吃掉68400K=68.4M内存,注意,这只是针对全局配置, 还没有包含布局系统等。

2 开启缓存
多次刷新刚才那个方法,发现产生的文件只有220K。

问题:为何会如此?比对先后两次产生的文件代码:
Magento全局配置文件结构

从缓存中获取的文件,admin adminhtml install stores crontab websites节点不见了。于是就产生了一个很大的困惑,如果开启了缓存,那么如何获取某个店铺的配置(因为缓存取回的配置没有店铺的设置)?

下面我们运行如下代码:

$xml = Mage::getConfig()->getNode('stores');
file_put_contents('D:/config_store.xml',$xml->asXml());

发现,它输出:

<store>
	<default></defatul>
	<admin></admin>
</store>

刚才消失的store节点这里获取出来了。

看起来,我们必须搞明白缓存对象干了什么事情。

首先进入App的run方法,它首先运行baseInit(),它里面有:

        $cacheInitOptions = is_array($options) && array_key_exists('cache', $options) ? $options['cache'] : array(); //空
        $this->_initCache($cacheInitOptions);

注意,这里的$cacheInitOptions是空的。然后调用:

    protected function _initCache(array $cacheInitOptions = array())
    {
        $this->_isCacheLocked = true;
        $options = $this->_config->getNode('global/cache');
        if ($options) {
            $options = $options->asArray();
        } else {
            $options = array();
        }
        $options = array_merge($options, $cacheInitOptions);
        $this->_cache = Mage::getModel('core/cache', $options);
        $this->_isCacheLocked = false;
        return $this;
    }

可以看到,这里初始化了一个core/cache对象。另外,我们可以知道,它会从global/cache中获取配置信息,关于缓存配置的都是在这里设置。

接下看看Mage_Core_Model_Cache的构造函数:

    public function __construct(array $options = array())
    {
    	    // ../var/cache
        $this->_defaultBackendOptions['cache_dir'] = Mage::getBaseDir('cache');
        /**
         * Initialize id prefix
         */
        // id_prefix
        $this->_idPrefix = isset($options['id_prefix']) ? $options['id_prefix'] : '';
        // id_prefix没有指定,但是设置了prefix,那么 id_prefix = prefix
        if (!$this->_idPrefix && isset($options['prefix'])) {
            $this->_idPrefix = $options['prefix'];
        }
        // 如果_idPrefix还为空,MD5 ../etc目录,然后取前3个字符,然后再加下划线作为_idPrefix
        if (empty($this->_idPrefix)) {
            $this->_idPrefix = substr(md5(Mage::getConfig()->getOptions()->getEtcDir()), 0, 3).'_';
        }

        $backend    = $this->_getBackendOptions($options);
        $frontend   = $this->_getFrontendOptions($options);

        $this->_frontend = Zend_Cache::factory('Varien_Cache_Core', $backend['type'], $frontend, $backend['options'],
            true, true, true
        );

        if (isset($options['request_processors'])) {
            $this->_requestProcessors = $options['request_processors'];
        }

        if (isset($options['disallow_save'])) {
            $this->_disallowSave = $options['disallow_save'];
        }
    }

最终使用Zend_Cache生成缓存对象。$backend得到的是一个包含两个字段的数组,一个是type,表示存储类型,另一个是options,对应这个存储类型的选项。具体需要继续跟踪进入:

   protected function _getBackendOptions(array $cacheOptions)
    {
        $enable2levels = false;
        // 存储类型,默认为 File
        $type   = isset($cacheOptions['backend']) ? $cacheOptions['backend'] : $this->_defaultBackend;
        // 检查是否提供了backend_options
        if (isset($cacheOptions['backend_options']) && is_array($cacheOptions['backend_options'])) {
            $options = $cacheOptions['backend_options'];
        } else {
            $options = array();
        }
	// 根据$type,获取$backendType,如果配置中没有给出backend_options,那么$options就是空的,但是根据不同的类型,还是可能产生其它$option
        $backendType = false;
        switch (strtolower($type)) {
            case 'apc':
                if (extension_loaded('apc') && ini_get('apc.enabled')) {
                    $enable2levels = true;
                    $backendType = 'Apc';
                }
                break;
            case 'database':
                $backendType = 'Varien_Cache_Backend_Database';
                $options = $this->getDbAdapterOptions();
                break;
            default:
                if ($type != $this->_defaultBackend) {
                }
        }

        $backendOptions = array('type' => $backendType, 'options' => $options);
        if ($enable2levels) {
            $backendOptions = $this->_getTwoLevelsBackendOptions($backendOptions, $cacheOptions);
        }
        return $backendOptions;
    }

$options的中的值根据不同存储类型会不同(还受到配置中是否给出backend_options配置的影响),可以推导出配置结构:

<global>
	<cache>
		<backend></backend>
		<backend_options>
                        <memcached>只有backend为memcached时</memcached>	
                </backend_options>

                <auto_refresh_fast_cache><auto_refresh_fast_cache>
                <slow_backend><slow_backend>
                <slow_backend_options><slow_backend_options>
                <slow_backend_store_data><slow_backend_store_data>
                <cache_db_complete_path>只有backend为sqlite时</ cache_db_complete_path/>
                <slow_backend_store_data>只有backend为database时</slow_backend_store_data>

                <frontend_options>
	            <caching>不设置默认为true</caching>
                    <lifetime>不设置默认是7200</lifetime>
                    <automatic_cleaning_factor>不设置默认为0</automatic_cleaning_factor>
                </frontend_options>
        </cache>
</global>

如果类型是memcached时,backend_options应该需要提供memcached节点。

注意_getBackendOptions函数返回$backendOptions前,还经过了_getTwoLevelsBackendOptions方法的处理(除了类型是File和Database时),所以最终返回的数据:

$options['fast_backend'] //存储类型,根据backend节点转换而来
$options['fast_backend_options'] //只有backend节点为database和memcached时有内容
$options['fast_backend_custom_naming']  = true;
$options['fast_backend_autoload']       = true;
$options['slow_backend_custom_naming']  = true;
$options['slow_backend_autoload']       = true;

$options['auto_refresh_fast_cache']  //来自auto_refresh_fast_cache节点,否则为false
$options['slow_backend'] //来自slow_backend节点,否则为File
$options['slow_backend_options'] // 来自slow_backend_options节点,否则为默认
$options['slow_backend_options']['store_data']//来自slow_backend_store_data,只有backend是database时,不过看起来它不可进入

回到缓存对象的构造函数,接下来执行_getFrontendOptions函数,它去寻找frontend_options节点,设置是否缓存 和 缓存时间,参考以上给出的配置文件。

接下执行:

$this->_frontend = Zend_Cache::factory('Varien_Cache_Core', $backend['type'], $frontend, $backend['options'],
            true, true, true
        );

实际利用Zend_Cache生成了一个缓存对象(Varien_Cache_Core继承自Zend_Cache_Core),它保存到缓存对象的_frontend中(****)。

通过App的_initCache,它的_cache字段都保持了一份Mage_Core_Model_Cache对象的引用(注意它内部的__frontend,它应该才是核心)。

现在把目光转移回到App的run方法中,看如下代码:

        if ($this->_cache->processRequest()) {
            $this->getResponse()->sendResponse();
        } else {}

这里调用缓存对象的processRequest,如果顺利,可以直接响应。那么去看看processRequest方法:

    public function processRequest()
    {
        if (empty($this->_requestProcessors)) {
            return false;
        }

        $content = false;
        foreach ($this->_requestProcessors as $processor) {
            $processor = $this->_getProcessor($processor);
            if ($processor) {
                $content = $processor->extractContent($content);
            }
        }

        if ($content) {
            Mage::app()->getResponse()->appendBody($content);
            return true;
        }
        return false;
    }

马上就有疑问,_requestProcessors如何被设置的,好吧,在构造函数中,刚才少说了如下代码:

// Mage_Core_Model_Cache
        if (isset($options['request_processors'])) {
            $this->_requestProcessors = $options['request_processors'];
        }

request_processors是在配置文件的cache中指定的:

	<global>
		<cache>
	<request_processors></request_processors>
</cache>
</global>

如果指定了,那么就使用它处理响应。这个处理器至少有extractContent方法,看起来应该是和全页缓存相关。我试图去搜索extractContent,没有找到这个方法,结论是,Magento CE还没有提供全页缓存,这个也是这种插件热卖的原因了。

如果进入System->Configuration->ADVANCED->System,你将看到:
Magento后台设置全页缓存
这个配置和我这里说的全页缓存不是一个概念。这里的zend_page_cache是Zend Server提供的一个扩展,具体怎么搞就没有研究了。
Zend_Page_Cahce配置
这个探讨先到这里。我们继续回到App的_initModules()方法中:

    protected function _initModules()
    {
        if (!$this->_config->loadModulesCache()) {
            $this->_config->loadModules();
 
            $this->_config->loadDb();
            $this->_config->saveCache();
        }
        return $this;
    }

这里的saveCache()方法是首次开始缓存。既然如此,那么继续:

    public function saveCache($tags=array())
    {
        if (!Mage::app()->useCache('config')) {
            return $this;
        }
	//为缓存打标签
        if (!in_array(self::CACHE_TAG, $tags)) {
            $tags[] = self::CACHE_TAG;
        }
        $cacheLockId = $this->_getCacheLockId();
	//这是上锁保护 如果缓存正在进行,那么就被取消
        if ($this->_loadCache($cacheLockId)) {
            return $this;
        }
	// … 省略
    }

这里首先使用App的useCache方法检查是否启用了缓存:

//Mage_Core_Model_App
    public function useCache($type=null)
    {
        return $this->_cache->canUse($type);
}
//Mage_Core_Model_Cache
    public function canUse($typeCode)
{
	// _allowedCacheOptions为空
        if (is_null($this->_allowedCacheOptions)) {
            $this->_initOptions();
        }

        if (empty($typeCode)) {
            return $this->_allowedCacheOptions;
        } else {
            if (isset($this->_allowedCacheOptions[$typeCode])) {
                return (bool)$this->_allowedCacheOptions[$typeCode];
            } else {
                return false;
            }
        }
}

    protected function _initOptions()
{
	// OPTIONS_CACHE_ID->core_cache_options 这里首先从缓存中获取这个值
        $options = $this->load(self::OPTIONS_CACHE_ID);
        if ($options === false) { //没有获取值
	    //从数据库获取值
            $options = $this->_getResource()->getAllOptions();
            if (is_array($options)) {
                $this->_allowedCacheOptions = $options;
	        //把值缓存起来
                $this->save(serialize($this->_allowedCacheOptions), self::OPTIONS_CACHE_ID);
            } else {
                $this->_allowedCacheOptions = array();
            }
        } else {
	    //取到了值
            $this->_allowedCacheOptions = unserialize($options);
        }

        if (Mage::getConfig()->getOptions()->getData('global_ban_use_cache')) {
            foreach ($this->_allowedCacheOptions as $key => $val) {
                $this->_allowedCacheOptions[$key] = false;
            }
        }

        return $this;
    }

这里先开个小差,哪些东西可以设置缓存,后台可以指定:
Magento缓存管理

这些设置保存到表core_cache_option中:
Magento缓存配置表
实际canUse就是返回对应的value值,1表示使用缓存,0表示不使用。另外,还有core_cache和core_cache_tag这两个表和core_cache_option没有任何干系,它们是使用数据库缓存时保存缓存数据的地方。

回到saveCache方法:

//Mage_Core_Model_Config
    public function saveCache($tags=array())
    {
        if (!Mage::app()->useCache('config')) {
            return $this;
        }
	//为缓存打标签  保存的时候可以打标签
        if (!in_array(self::CACHE_TAG, $tags)) {
            $tags[] = self::CACHE_TAG;
        }
	// Config对象在构造函数中$this->setCacheId('config_global');设置了ID
	// 这里获取config_global.lock,如果能load进来,直接就返回了,说明在上锁
        $cacheLockId = $this->_getCacheLockId();
        if ($this->_loadCache($cacheLockId)) {
            return $this;
        }
/*
$_cacheSections = array(
        'admin'     => 0,
        'adminhtml' => 0,
        'crontab'   => 0,
        'install'   => 0,
        'stores'    => 1,
        'websites'  => 0
    );
*/
        if (!empty($this->_cacheSections)) {
            $xml = clone $this->_xml;
	    //根据_cacheSections数组把全局配置文件拆分
            foreach ($this->_cacheSections as $sectionName => $level) {
                $this->_saveSectionCache($this->getCacheId(), $sectionName, $xml, $level, $tags);
                unset($xml->$sectionName);
            }
	    // config_global 是被剥离后剩余部分
            $this->_cachePartsForSave[$this->getCacheId()] = $xml->asNiceXml('', false);
        } else {
            return parent::saveCache($tags);
        }

        $this->_saveCache(time(), $cacheLockId, array(), 60); //上锁
        //移除打了CONFIG标签的cache(全部配置相关的缓存,全部打了这个标志,默认)
        $this->removeCache();
        foreach ($this->_cachePartsForSave as $cacheId => $cacheData) {
            $this->_saveCache($cacheData, $cacheId, $tags, $this->getCacheLifetime());
/*
    protected function _saveCache($data, $id, $tags=array(), $lifetime=false)
    {
        return Mage::app()->saveCache($data, $id, $tags, $lifetime);
    }
*/
        }
        unset($this->_cachePartsForSave);
        $this->_removeCache($cacheLockId); //解锁
        return $this;
}

    protected function _saveSectionCache($idPrefix, $sectionName, $source, $recursionLevel=0, $tags=array())
    {
        if ($source && $source->$sectionName) {
			// config_global_admin config_global_websites
            $cacheId = $idPrefix . '_' . $sectionName;
            if ($recursionLevel > 0) {
                foreach ($source->$sectionName->children() as $subSectionName => $node) {
                    $this->_saveSectionCache(
                        $cacheId, $subSectionName, $source->$sectionName, $recursionLevel-1, $tags
                    );
                }
            }
		    //部分保存的XML
            $this->_cachePartsForSave[$cacheId] = $source->$sectionName->asNiceXml('', false);
        }
        return $this;
    }

这部分代码总体上实现了把全局对象拆分成几段缓存:

config_global
config_global_admin
config_global_adminhtml
config_global_install
config_global_websites
config_global_stores_default
config_global_stores_admin
config_global_stores_german
config_global_stores_french

config_global是被拆了admin等之后剩余的XML。这些缓存全部打上了CONFIG这个Tag,Config中的removeCache方法实际就是移除所有打上了这个Tag的缓存。

生成缓存就这样够一段了。下面如何加载缓存。还是从App的run方法进入,它之中运行的baseInit主要是初始化环境(_initEnvironment),初始化基础配置(app/etc/config.xml和local.xml,由_initBaseConfig调用Config的loadBase完成,说明这两个文件的内容尽管已经缓存,但是每次都会被读取)和生成缓存对象,接下来的_initModules方法:

    protected function _initModules()
    {
        if (!$this->_config->loadModulesCache()) {
        }
        return $this;
}

实际调用Config的loadModulesCache方法加载缓存,如果能加载就使用加载的缓存文件:

//Mage_Core_Model_Config
    public function loadModulesCache()
    {
        if (Mage::isInstalled(array('etc_dir' => $this->getOptions()->getEtcDir()))) {
            if ($this->_canUseCacheForInit()) {
                $loaded = $this->loadCache();
                
                if ($loaded) {
                    $this->_useCache = true;
                    return true;
                }
            }
        }
        return false;
    }

这里重点是loadCache方法,这个负责加载缓存,如果成功加载使用_useCache标识在使用缓存:

// lib/Varien/Simplexml/Config
    public function loadCache()
    {
        if (!$this->validateCacheChecksum()) {
            return false;
        }

        $xmlString = $this->_loadCache($this->getCacheId());
        $xml = simplexml_load_string($xmlString, $this->_elementClass);
        if ($xml) {
            $this->_xml = $xml;
            $this->setCacheSaved(true);
            return true;
        }

        return false;
    }

getCacheId()获取config_global,它会把这个缓存加载进来。所以从缓存拿回来的_xml只是一部分,这才解释了本文刚开始遇到的疑问。可是新疑问又来了,既然是部分配置,那么如何获取店铺的配置呢?

首先是获取配置的用法:

$config->getNode('admin');
$config->getNode('stores');
$config->getNode('stores/default');

进入getNode()方法就可以看到,它根据第一个字段,相应的从缓存中取出缓存的内容。注意,其它获取配置的包装方法,都是间接使用getNode()方法,比如Mage::getStoreConfig()方法,实际调用Mage_Core_Model_Store的getConfig方法,而这个方法内部就是调用getNode:

    public function getConfig($path)
    {
        $fullPath = 'stores/' . $this->getCode() . '/' . $path;
        $data = $config->getNode($fullPath);
    }

最后总结一下Magento中使用cache的方法:

//缓存一块数据
saveCache($data, $id, $tags=array(), $lifeTime=false)
//根据ID加载缓存
loadCache($id)
//根据ID删除缓存
removeCache($id)
//根据TAGS清楚缓存
cleanCache($tags=array())

来一段测试程序:

		$data = "12345678901234567890000000";
		$id = "Test_Cache";
		$tags = array('xTest','xCache');
		
		$fromCache = Mage::app()->loadCache($id);
		if($fromCache){
			echo "From cache---><br />";
			echo $fromCache;
			Mage::app()->removeCache($id);
		}else{
			echo "No cache ---><br />";
			Mage::app()->saveCache($data, $id, $tags);
		}

Magento缓存文件

Magento缓存文件内容

这种缓存的功能是ZF提供的。对于全局配置文件,如果不缓存,每次都读取合并很多文件,这个过程将产生大量的IO,如果缓存了,将可以减少大部分的IO操作和减少计算资源,但是还是要把缓存读入内存,如果能够把这些缓存放入共享内存中,理论上应该可以提升性能(减少了从磁盘调人内存这个IO操作,所以把缓存放入磁盘和放入共享内存,性能提升不明显的原因就在这里),如缓存已经在内存中,不用每次都调用文件写入内存,但是获取缓存转换成PHP对象仍然占有比较多内存,所以Magento是很非常耗内存,并发一多,就会很明显。

永久链接:http://blog.ifeeline.com/715.html
原创文章,转载务必保留出处。