使用缓存提高性能
最后更新于:2022-04-02 05:13:58
[TOC]
# 使用缓存提高性能
Phalcon提供`Phalcon\Cache`类,允许更快地访问常用或已处理的数据。`Phalcon\Cache`是用C语言编写的,在从后端获取项目时可以实现更高的性能并减少开销。此类使用前端和后端组件的内部结构。前端组件充当输入源或接口,而后端组件为类提供存储选项。
## 什么时候使用缓存?
虽然这个组件非常快,但在不需要的情况下实现它可能会导致性能损失而不是获得。我们建议您在使用缓存之前检查此案例:
* 您正在进行复杂的计算,每次返回相同的结果(不经常更改)
* 您正在使用大量帮助程序,并且生成的输出几乎总是相同的
* 您正在不断访问数据库数据,这些数据很少更改
>[warning] **NOTE** 即使在实现缓存之后,您也应该检查缓存在一段时间内的命中率。 这可以很容易地完成,特别是在Memcache或Apc的情况下,使用后端提供的相关工具。
## 缓存行为
缓存过程分为两部分:
* **前端**:此部分负责检查密钥是否已过期,并在存储之前和从后端检索数据后对数据执行其他转换
* **后端**: 该部分负责通信,写入/读取前端所需的数据。
## 工厂
实例化前端或后端适配器可以通过两种方式实现:
传统方式
```php
172800,
]
);
// 创建将从“输出”缓存到“文件”后端的组件
// 设置缓存文件目录 - 将'/'保留在文件夹值的末尾非常重要
$cache = new BackFile(
$frontCache,
[
'cacheDir' => '../app/cache/',
]
);
```
或使用Factory对象,如下所示:
```php
172800,
'adapter' => 'data',
];
$frontendCache = FFactory::load($options);
$options = [
'cacheDir' => '../app/cache/',
'prefix' => 'app-data',
'frontend' => $frontendCache,
'adapter' => 'file',
];
$backendCache = BFactory::load($options);
```
## 缓存输出片段
输出片段是一段HTML或文本,按原样缓存并按原样返回。从`ob_ *`函数或PHP输出自动捕获输出,以便将其保存在缓存中。以下示例演示了此类用法。它接收PHP生成的输出并将其存储到文件中。该文件的内容每172,800秒(2天)刷新一次。
这种缓存机制的实现允许我们通过在调用这段代码时不执行辅助`Phalcon\Tag::linkTo()`调用来获得性能。
```php
172800,
]
);
// 创建将从“输出”缓存到“文件”后端的组件
// 设置缓存文件目录 - 将'/'保留在文件夹值的末尾非常重要
$cache = new BackFile(
$frontCache,
[
'cacheDir' => '../app/cache/',
]
);
// 获取/设置缓存文件为../app/cache/my-cache.html
$content = $cache->start('my-cache.html');
// 如果 $content 为null,则将为缓存生成内容
if ($content === null) {
// 打印日期和时间
echo date('r');
// 生成注册操作的链接
echo Tag::linkTo(
[
'user/signup',
'Sign Up',
'class' => 'signup-button',
]
);
// 将输出存储到缓存文件中
$cache->save();
} else {
// 回显缓存的输出
echo $content;
}
```
>[warning] **NOTE** 在上面的示例中,我们的代码保持不变,将输出回显给用户,就像之前一样。 我们的缓存组件透明地捕获该输出并将其存储在缓存文件中(当生成缓存时)或者将其发送回从先前调用预编译的用户,从而避免昂贵的操作。
## 缓存任意数据
仅缓存数据对于您的应用程序同样重要。缓存可以通过重用常用(但未更新)的数据来减少数据库负载,从而加快应用程序的速度。
### File后端示例
其中一个缓存适配器是`File`。此适配器的唯一关键区域是缓存文件的存储位置。这由`cacheDir`选项控制,该选项必须在其末尾加上反斜杠。
```php
172800,
]
);
// 创建将从“输出”缓存到“文件”后端的组件
// 设置缓存文件目录 - 将'/'保留在文件夹值的末尾非常重要
$cache = new BackFile(
$frontCache,
[
'cacheDir' => '../app/cache/',
]
);
$cacheKey = 'robots_order_id.cache';
// 尝试获取缓存记录
$robots = $cache->get($cacheKey);
if ($robots === null) {
// 由于缓存过期或数据不存在,$robots为 null
// 进行数据库调用并填充变量
$robots = Robots::find(
[
'order' => 'id',
]
);
// 将其存储在缓存中
$cache->save($cacheKey, $robots);
}
// 使用 $robots :)
foreach ($robots as $robot) {
echo $robot->name, '\n';
}
```
### Memcached后端示例
当我们使用Memcached后端时,上面的示例略有变化(特别是在配置方面)。
```php
3600,
]
);
// 创建将“数据”缓存到“Memcached”后端的组件
// Memcached连接设置
$cache = new BackMemCached(
$frontCache,
[
'servers' => [
[
'host' => '127.0.0.1',
'port' => '11211',
'weight' => '1',
]
]
]
);
$cacheKey = 'robots_order_id.cache';
// 尝试获取缓存记录
$robots = $cache->get($cacheKey);
if ($robots === null) {
// 由于缓存过期或数据不存在,$robots为 null
// 进行数据库调用并填充变量
$robots = Robots::find(
[
'order' => 'id',
]
);
// 将其存储在缓存中
$cache->save($cacheKey, $robots);
}
// 使用 $robots :)
foreach ($robots as $robot) {
echo $robot->name, '\n';
}
```
>[warning] **NOTE** 调用
';
save()
将返回一个布尔值,表示成功(true)或失败(false)。 根据您使用的后端,您需要查看相关日志以识别故障。
## 查询缓存
添加到缓存的元素由key唯一标识。对于File后端,key是实际文件名。要从缓存中检索数据,我们只需使用唯一key调用它。如果key不存在,则get方法将返回null。
```php
get('myProducts');
```
如果您想知道缓存中存储了哪些key,可以调用`queryKeys`方法:
```php
queryKeys();
foreach ($keys as $key) {
$data = $cache->get($key);
echo 'Key=', $key, ' Data=', $data;
}
// 以“my-prefix”开头的缓存中的查询key
$keys = $cache->queryKeys('my-prefix');
```
## 从缓存中删除数据
有时您需要强制使缓存条目无效(由于缓存数据中的更新)。唯一的要求是知道数据存储的key。
```php
delete('someKey');
$keys = $cache->queryKeys();
// 从缓存中删除所有项目
foreach ($keys as $key) {
$cache->delete($key);
}
```
## 检查缓存是否存在
可以使用给定的key检查缓存是否已存在:
```php
exists('someKey')) {
echo $cache->get('someKey');
} else {
echo 'Cache does not exists!';
}
```
## 生命周期
生命周期是缓存可以在没有过期的情况下生存的时间(以秒为单位)。默认情况下,所有创建的缓存都使用前端创建中设置的生存期。您可以在从缓存中创建或检索数据时设置特定生命周期:
检索时设置生命周期:
```php
get($cacheKey, 3600);
if ($robots === null) {
$robots = 'some robots';
// 将其存储在缓存中
$cache->save($cacheKey, $robots);
}
```
保存时设置生命周期:
```php
get($cacheKey);
if ($robots === null) {
$robots = 'some robots';
// 保存数据时设置缓存
$cache->save($cacheKey, $robots, 3600);
}
```
## 多级缓存
缓存组件的此功能允许开发人员实现多级缓存。这个新功能非常有用,因为您可以将相同的数据保存在具有不同生命周期的多个缓存位置中,首先从具有较快适配器的缓存中读取,然后以最慢的一个读取直到数据到期:
```php
3600,
]
);
$fastFrontend = new DataFrontend(
[
'lifetime' => 86400,
]
);
$slowFrontend = new DataFrontend(
[
'lifetime' => 604800,
]
);
// 后端从最快到最慢注册
$cache = new Multiple(
[
new ApcCache(
$ultraFastFrontend,
[
'prefix' => 'cache',
]
),
new MemcacheCache(
$fastFrontend,
[
'prefix' => 'cache',
'host' => 'localhost',
'port' => '11211',
]
),
new FileCache(
$slowFrontend,
[
'prefix' => 'cache',
'cacheDir' => '../app/cache/',
]
),
]
);
// 保存,保存在每个后端
$cache->save('my-key', $data);
```
## 前端适配器
可用作缓存的接口或输入源的前端适配器是:
| 适配器 | 描述 |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Phalcon\Cache\Frontend\Output` | 从标准PHP输出中读取输入数据。 |
| `Phalcon\Cache\Frontend\Data` | 它用于缓存任何类型的PHP数据(大数组,对象,文本等)。数据在存储在后端之前被序列化。 |
| `Phalcon\Cache\Frontend\Base64` | 它用于缓存二进制数据。在存储在后端之前,使用`base64_encode`对数据进行序列化。 |
| `Phalcon\Cache\Frontend\Json` | 数据在存储在后端之前以JSON编码。检索后解码。此前端对于与其他语言或框架共享数据非常有用。 |
| `Phalcon\Cache\Frontend\Igbinary` | 它用于缓存任何类型的PHP数据(大数组,对象,文本等)。在存储在后端之前,使用`Igbinary`对数据进行序列化。 |
| `Phalcon\Cache\Frontend\None` | 它用于缓存任何类型的PHP数据而无需序列化它们。 |
### 实现自己的前端适配器
必须实现`Phalcon\Cache\FrontendInterface` 接口才能创建自己的前端适配器或扩展现有前端适配器。
## 后端适配器
可用于存储缓存数据的后端适配器是:
| 适配器 | 描述 | 信息 | 需要的扩展 |
| ------------------------------------ | ---------------------------------------------------- | ----------------------------------------- | -------------------------------------------------- |
| `Phalcon\Cache\Backend\Apc` | 将数据存储到Alternative PHP Cache(APC) | [APC](http://php.net/apc) | [APC](http://pecl.php.net/package/APC) |
| `Phalcon\Cache\Backend\Apcu` |将数据存储到APCu(没有操作码缓存的APC) | [APCu](http://php.net/apcu) | [APCu](http://pecl.php.net/package/APCu) |
| `Phalcon\Cache\Backend\File` | 将数据存储到本地纯文件。 | | |
| `Phalcon\Cache\Backend\Libmemcached` | 将数据存储到memcached服务器。 | [Memcached](http://www.php.net/memcached) | [Memcached](http://pecl.php.net/package/memcached) |
| `Phalcon\Cache\Backend\Memcache` | 将数据存储到memcached服务器。 | [Memcache](http://www.php.net/memcache) | [Memcache](http://pecl.php.net/package/memcache) |
| `Phalcon\Cache\Backend\Memory` | 将数据存储到内存 | | |
| `Phalcon\Cache\Backend\Mongo` | 将数据存储到Mongo数据库。 | [MongoDB](http://mongodb.org/) | [Mongo](http://mongodb.org/) |
| `Phalcon\Cache\Backend\Redis` | 将数据存储到Redis. | [Redis](http://redis.io/) | [Redis](http://pecl.php.net/package/redis) |
| `Phalcon\Cache\Backend\Xcache` | 将数据存储到XCache. | [XCache](http://xcache.lighttpd.net/) | [XCache](http://pecl.php.net/package/xcache) |
>[warning] **NOTE** 在PHP 7中使用基于phalcon apc的适配器类,您需要从pecl安装`apcu`和`apcu_bc`包。现在在Phalcon
中,您可以将`*\Apc`类切换为`*\ Apcu`并删除`apcu_bc`。请记住,在Phalcon 4中,我们很可能会删除所有`*\Apc`类。
### 工厂
有许多后端适配器(请参阅后端适配器)。您使用的那个将取决于您的应用程序的需求。下面的示例使用`adapter`选项加载后端缓存适配器类,如果前端将作为数组提供,它将调用前端缓存工厂
```php
'app-data',
'frontend' => new Data(),
'adapter' => 'apc',
];
$backendCache = Factory::load($options);
```
### 实现自己的后端适配器
必须实现 `Phalcon\Cache\BackendInterface` 接口才能创建自己的后端适配器或扩展现有的后端适配器。
### File后端选项
此后端将缓存的内容存储到本地服务器的文件中。此后端的可用选项包括:
| 选项 | 描述 |
| ---------- | ------------------------------------ |
| `prefix` | 自动添加到缓存key的前缀。 |
| `cacheDir` | 一个可写目录,将在其上放置缓存文件。 |
### Libmemcached后端选项
此后端将缓存的内容存储在memcached服务器上。每个默认持久性memcached连接池都使用。此后端的可用选项包括:
**常规选项**
| 选项 | 描述 |
| --------------- | ------------------------------------------------------------ |
| `statsKey` | 用于跟踪缓存的key。 |
| `prefix` | 自动添加到缓存key的前缀。 |
| `persistent_id` | 要创建在请求之间保持不变的实例,请使用persistent_id为实例指定唯一ID。 |
**服务端选项**
| 选项 | 描述 |
| -------- | ------------------------------------------------------------ |
| `host` | The `memcached` host. |
| `port` | The `memcached` port. |
| `weight` | 要创建在请求之间保持不变的实例,请使用persistent_id为实例指定唯一ID。 |
**客户端选项**
用于设置Memcached选项。有关更多信息,请参阅`Memcached::setOptions`。
**示例**
```php
172800,
]
);
// 创建缓存设置memcached连接选项
$cache = new Libmemcached(
$frontCache,
[
'servers' => [
[
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 1,
],
],
'client' => [
\Memcached::OPT_HASH => \Memcached::HASH_MD5,
\Memcached::OPT_PREFIX_KEY => 'prefix.',
],
'persistent_id' => 'my_app_cache',
]
);
```
### Memcache后端选项
此后端将缓存的内容存储在memcached服务器上。此后端的可用选项包括:
| 选项 | 描述 |
| ------------ | --------------------------- |
| `prefix` | 自动添加到缓存key的前缀。 |
| `host` | memcached host地址。 |
| `port` | memcached端口。 |
| `persistent` | 创建与memcached的持久连接? |
### APC后端选项
此后端将缓存内容存储在Alternative PHP Cache([APC](http://php.net/apc))上。此后端的可用选项包括:
| 选项 | 描述 |
| -------- | ------------------------- |
| `prefix` | 自动添加到缓存key的前缀。 |
### APCU后端选项
此后端将缓存内容存储在Alternative PHP Cache([APCU](http://php.net/apcu))上。此后端的可用选项包括:
| 选项 | 描述 |
| -------- | ------------------------- |
| `prefix` | 自动添加到缓存key的前缀。 |
### Mongo后端选项
此后端将缓存内容存储在MongoDB服务器([MongoDB](http://mongodb.org/))上。此后端的可用选项包括:
| 选项 | 描述 |
| ------------ | ------------------------- |
| `prefix` | 自动添加到缓存key的前缀。 |
| `server` | MongoDB连接字符串。 |
| `db` | Mongo数据库名称。 |
| `collection` | Mongo集合在数据库中。 |
### XCache后端选项
此后端将在XCache([XCache](http://xcache.lighttpd.net/))上存储缓存的内容。此后端的可用选项包括:
| 选项 | 描述 |
| -------- | ------------------------- |
| `prefix` | 自动添加到缓存key的前缀。 |
### Redis后端选项
此后端将缓存内容存储在Redis服务器([Redis](http://redis.io/))上。此后端的可用选项包括:
| 选项 | 描述 |
| ------------ | ------------------------------------------------- |
| `prefix` | 自动添加到缓存key的前缀。 |
| `host` | Redis host地址 |
| `port` | Redis 端口 |
| `auth` | 用于向受密码保护的Redis服务器进行身份验证的密码。 |
| `persistent` | 创建与Redis的持久连接。 |
| `index` | 要使用的Redis数据库的索引。 |
Phalcon孵化器中有更多适用于此组件的适配器