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

Phalcon提供的 Phalcon\Cache 类可以更快地接入获取使用频繁或者已经被处理的数据。 Phalcon\Cache 是用C来编写的,因此有着更高的性能并且能够减少从后端获取昂价资源所带来的负载。 这个类使用了由前端和后端组件组成的内部结构。前端组件如输入源或者接口,后端组件则为这个类提供了存储的选项。

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.

什么情况下使用缓存?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

温馨提示 即使使用了这些缓存,你仍然应该定期检测缓存的命中率。 通过后台提供的相关工具,这一点很容易做得到,特别是使用Memcache或者APC时。

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:

前端: 此部分负责检测是否key已失效并且在保存数据和抓取数据后提供额外的转换操作。 后端: 此部分负责通讯,并根据前端进行数据的读/写。

  • 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-
  • Backend: This part is responsible for communicating, writing/reading the data required by the frontend.

缓存输出片段Caching Output Fragments

输出片段是指一小块缓存和返回都一样的HTML或者文本内容。输出的内容应该是能自动 被 ob_* 函数捕获或者直接是PHP输出,这样才能缓存起来。以下实例演示了这样的使用。 它接收PHP生成的页面输出并保存在一个文件里面。缓存文件的内容每隔172800秒(2天)刷新一次。

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).

使用这个缓存机制,无论何时调用这块代码,我们都可以通过避免重复执行辅助插件 Phalcon\Tag::linkTo 从而获得更高的性能。

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.

  1. <?php
  2. use Phalcon\Tag;
  3. use Phalcon\Cache\Backend\File as BackFile;
  4. use Phalcon\Cache\Frontend\Output as FrontOutput;
  5. //Create an Output frontend. Cache the files for 2 days
  6. $frontCache = new FrontOutput(array(
  7. "lifetime" => 172800
  8. ));
  9. // Create the component that will cache from the "Output" to a "File" backend
  10. // Set the cache file directory - it's important to keep the "/" at the end of
  11. // the value for the folder
  12. $cache = new BackFile($frontCache, array(
  13. "cacheDir" => "../app/cache/"
  14. ));
  15. // Get/Set the cache file to ../app/cache/my-cache.html
  16. $content = $cache->start("my-cache.html");
  17. // If $content is null then the content will be generated for the cache
  18. if ($content === null) {
  19. //Print date and time
  20. echo date("r");
  21. //Generate a link to the sign-up action
  22. echo Tag::linkTo(
  23. array(
  24. "user/signup",
  25. "Sign Up",
  26. "class" => "signup-button"
  27. )
  28. );
  29. // Store the output into the cache file
  30. $cache->save();
  31. } else {
  32. // Echo the cached output
  33. echo $content;
  34. }

温馨提示 在上面的实例中,我们的代码维持不变,即输出给用户的内容和之前展示的内容是一样的。我们的缓存组件 以透明的方式捕获了页面输出并保存在缓存文件(当缓存生成时)或者在早期的一次调用时将它发送回用户预编译,故而可以避免高昂的操作。

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

其中一个缓存适配器是文件’File’。文件适配器的配置中只需要一个key:指明缓存文件存放的目录位置。 这个配置通过cacheDir选项控制,必须,且要以反斜杠结尾。

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.

  1. <?php
  2. use Phalcon\Cache\Backend\File as BackFile;
  3. use Phalcon\Cache\Frontend\Data as FrontData;
  4. // Cache the files for 2 days using a Data frontend
  5. $frontCache = new FrontData(array(
  6. "lifetime" => 172800
  7. ));
  8. // Create the component that will cache "Data" to a "File" backend
  9. // Set the cache file directory - important to keep the "/" at the end of
  10. // of the value for the folder
  11. $cache = new BackFile($frontCache, array(
  12. "cacheDir" => "../app/cache/"
  13. ));
  14. // Try to get cached records
  15. $cacheKey = 'robots_order_id.cache';
  16. $robots = $cache->get($cacheKey);
  17. if ($robots === null) {
  18. // $robots is null because of cache expiration or data does not exist
  19. // Make the database call and populate the variable
  20. $robots = Robots::find(array("order" => "id"));
  21. // Store it in the cache
  22. $cache->save($cacheKey, $robots);
  23. }
  24. // Use $robots :)
  25. foreach ($robots as $robot) {
  26. echo $robot->name, "\n";
  27. }

Memcached 后端存储器例子Memcached Backend Example

当我们改用Memcached作为后端存储器时,上面的实例改动很轻微(特别就配置而言)。

The above example changes slightly (especially in terms of configuration) when we are using a Memcached backend.

  1. <?php
  2. use Phalcon\Cache\Frontend\Data as FrontData;
  3. use Phalcon\Cache\Backend\Libmemcached as BackMemCached;
  4. //Cache data for one hour
  5. $frontCache = new FrontData(array(
  6. "lifetime" => 3600
  7. ));
  8. // Create the component that will cache "Data" to a "Memcached" backend
  9. // Memcached connection settings
  10. $cache = new BackMemCached($frontCache, array(
  11. "servers" => array(
  12. array(
  13. "host" => "127.0.0.1",
  14. "port" => "11211",
  15. "weight" => "1"
  16. )
  17. )
  18. ));
  19. // Try to get cached records
  20. $cacheKey = 'robots_order_id.cache';
  21. $robots = $cache->get($cacheKey);
  22. if ($robots === null) {
  23. // $robots is null because of cache expiration or data does not exist
  24. // Make the database call and populate the variable
  25. $robots = Robots::find(array("order" => "id"));
  26. // Store it in the cache
  27. $cache->save($cacheKey, $robots);
  28. }
  29. // Use $robots :)
  30. foreach ($robots as $robot) {
  31. echo $robot->name, "\n";
  32. }

查询缓存Querying the cache

添加到缓存的元素根据唯一的key进行识别区分。这使用文件缓存作为后端时,key就是实际的文件名。 为了从缓存中获得数据,我们仅仅需要通过唯一的key调用即可。如果key不存在,get方法将会返回null。

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.

  1. <?php
  2. // Retrieve products by key "myProducts"
  3. $products = $cache->get("myProducts");

如果你想知道在缓存中存放了哪些key,你可以调用queryKeys方法:

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

  1. <?php
  2. // Query all keys used in the cache
  3. $keys = $cache->queryKeys();
  4. foreach ($keys as $key) {
  5. $data = $cache->get($key);
  6. echo "Key=", $key, " Data=", $data;
  7. }
  8. //Query keys in the cache that begins with "my-prefix"
  9. $keys = $cache->queryKeys("my-prefix");

删除缓存数据 Deleting data from the cache

有些时机你需要强制废除一个缓存的实体(如对被缓存的数据进行了更新)。 而仅仅需要做的只是知道对应缓存的数据存放于哪个key即可。

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.

  1. <?php
  2. // Delete an item with a specific key
  3. $cache->delete("someKey");
  4. // Delete all items from the cache
  5. $keys = $cache->queryKeys();
  6. foreach ($keys as $key) {
  7. $cache->delete($key);
  8. }

检查缓存是否存在 Checking cache existence

也有可能需要根据一个给定的key来判断缓存是否存在:

It is possible to check if a cache already exists with a given key:

  1. <?php
  2. if ($cache->exists("someKey")) {
  3. echo $cache->get("someKey");
  4. } else {
  5. echo "Cache does not exists!";
  6. }

有效期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:

  1. <?php
  2. $cacheKey = 'my.cache';
  3. //Setting the cache when getting a result
  4. $robots = $cache->get($cacheKey, 3600);
  5. if ($robots === null) {
  6. $robots = "some robots";
  7. // Store it in the cache
  8. $cache->save($cacheKey, $robots);
  9. }

在保存时设置有效期:

Setting the lifetime when saving:

  1. <?php
  2. $cacheKey = 'my.cache';
  3. $robots = $cache->get($cacheKey);
  4. if ($robots === null) {
  5. $robots = "some robots";
  6. //Setting the cache when saving data
  7. $cache->save($cacheKey, $robots, 3600);
  8. }

多级缓存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​:

  1. <?php
  2. use Phalcon\Cache\Multiple;
  3. use Phalcon\Cache\Backend\Apc as ApcCache;
  4. use Phalcon\Cache\Backend\File as FileCache;
  5. use Phalcon\Cache\Frontend\Data as DataFrontend;
  6. use Phalcon\Cache\Backend\Memcache as MemcacheCache;
  7. $ultraFastFrontend = new DataFrontend(array(
  8. "lifetime" => 3600
  9. ));
  10. $fastFrontend = new DataFrontend(array(
  11. "lifetime" => 86400
  12. ));
  13. $slowFrontend = new DataFrontend(array(
  14. "lifetime" => 604800
  15. ));
  16. //Backends are registered from the fastest to the slower
  17. $cache = new Multiple(array(
  18. new ApcCache($ultraFastFrontend, array(
  19. "prefix" => 'cache',
  20. )),
  21. new MemcacheCache($fastFrontend, array(
  22. "prefix" => 'cache',
  23. "host" => "localhost",
  24. "port" => "11211"
  25. )),
  26. new FileCache($slowFrontend, array(
  27. "prefix" => 'cache',
  28. "cacheDir" => "../app/cache/"
  29. ))
  30. ));
  31. //Save, saves in every backend
  32. $cache->save('my-key', $data);

前端适配器Frontend Adapters

作为缓存的接口或者输入源的前端适配器有:

The available frontend adapters that are used as interfaces or input sources to the cache are:

AdapterDescriptionExample
OutputRead input data from standard PHP outputPhalcon\Cache\Frontend\Output
DataIt’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
Base64It’s used to cache binary data. The data is serialized using base64_encode before be stored in the backend.Phalcon\Cache\Frontend\Base64
JsonData 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
IgBinaryIt’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
NoneIt’s used to cache any kind of PHP data without serializing them.Phalcon\Cache\Frontend\None

自定义前端适配器Implementing your own Frontend adapters

为了创建你自己的前端适配器或者扩展已有的适配器,你必须 实现 Phalcon\Cache\FrontendInterface 接口。

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:

AdapterDescriptionInfoRequired ExtensionsExample
FileStores data to local plain files  Phalcon\Cache\Backend\File
MemcachedStores data to a memcached serverMemcachedmemcachePhalcon\Cache\Backend\Memcache
APCStores data to the Alternative PHP Cache (APC)APCAPC extensionPhalcon\Cache\Backend\Apc
MongoStores data to Mongo DatabaseMongoDbMongoPhalcon\Cache\Backend\Mongo
XCacheStores data in XCacheXCachexcache extensionPhalcon\Cache\Backend\Xcache

自定义后端适配器Implementing your own Backend adapters

为了创建你自己的后端适配器或者扩展已有的后端适配器,你必须 实现 Phalcon\Cache\BackendInterface 接口。

The Phalcon\Cache\BackendInterface interface must be implemented in order to create your own backend adapters or extend the existing ones.

文件后端存储器选项File Backend Options

此后端存储器把缓存内容存放到本地服务器的文件。对应的选项有:

This backend will store cached content into files in the local server. The available options for this backend are:

OptionDescription
prefixA prefix that is automatically prepended to the cache keys
cacheDirA writable directory on which cached files will be placed

Memcached 后端存储器选项Memcached Backend Options

此后端存储器将缓存的内容存放在memcached服务器。对应的选项有:

This backend will store cached content on a memcached server. The available options for this backend are:

OptionDescription
prefixA prefix that is automatically prepended to the cache keys
hostmemcached host
portmemcached port
persistentcreate a persistent connection to memcached?

APC 后端存储器选项APC Backend Options

此后端存储器将缓存内容存放到opcode缓存(APC)。对应的选项有:

This backend will store cached content on Alternative PHP Cache (APC). The available options for this backend are:

OptionDescription
prefixA prefix that is automatically prepended to the cache keys

Mongo 后端存储器选项Mongo Backend Options

此后端存储器将缓存内容存放到MongoDB服务器。对应的选项有:

This backend will store cached content on a MongoDB server. The available options for this backend are:

OptionDescription
prefixA prefix that is automatically prepended to the cache keys
serverA MongoDB connection string
dbMongo database name
collectionMongo collection in the database

XCache 后端存储器选项XCache Backend Options

此后端存储器将缓存内容存放到XCache (XCache)。对应的选项有:

This backend will store cached content on XCache (XCache). The available options for this backend are:

OptionDescription
prefixA prefix that is automatically prepended to the cache keys

Phalcon Incubator 上还有更多针对这个组件可用的适配器

There are more adapters available for this components in the Phalcon Incubator