我们有一个很大的CakePHP(目前是2.4.7)SAAS-app。它非常成熟,直到上周我们才对CakePHPs-core提供的功能产生任何实际问题。
上周末我们遇到了一个非常惊人的情况,我们的应用程序变得非常缓慢和错误。我们查看了所有类型的服务器监控,发现在过去几个小时内i / o统计数据暴涨。经过一番调查后,我们将问题分离到了Cake的' cake_core_method_cache '文件中。平均每天,此文件的大小为200 kb。上周末,它达到了约40万桶。
我们的部署例程的一部分是从app / tmp / cache和app / tmp / persistent文件夹中删除所有缓存文件。因为我们经常部署(每天几次),所以缓存会经常被清除。不幸的是,上周的假期暂停了我们的部署,看起来这是核心/缓存功能的问题。
所以,我的两个问题是:
a)有谁知道,为什么cake_core_method_cache会随着时间的推移而变大?
b)有没有其他可能解决这个问题,以便不断删除这个文件?
答案 0 :(得分:4)
CakePHP中对method_cache的唯一引用位于Dbo Source。这是一个在整个类中广泛使用的缓存,用于缓存(relatively) expensive quoting operations的结果,或者由a relevant docblock指示:
缓存由查询解析操作产生。 DboSource :: name()和DboSource :: conditions()的缓存结果将存储在此处。
考虑以下shell:
<?php
class SoShell extends AppShell {
function main() {
$this->Post = ClassRegistry::init('Post');
$this->Post->find('all', array(
'conditions' => array(
'find-this-text' => 'x'
)
));
debug(DboSource::$methodCache);
}
}
运行它,产生以下输出:
> Console/cake so
########## DEBUG ##########
array(
'name' => array(
'f5442d1f57be5d9d8ac80ae9613d5ff9' => '`database_name`',
'cfacfed443d6f30e67edf9bbcb06ce30' => '`posts`',
'e13d78515036382daf55fa083088c902' => '`Post`.`id`',
'aafd056e6d53878a75ab4ee3f18645a1' => '`Post`.`title`',
'4084e974416e3a7fb06e6a280721637b' => '`Post`.`body`',
'b4f1ad1de4cdc3a3f82e905f8dfd8673' => '`Post`.`created`',
'bfeffce70e344d7606e17c9ff24530b5' => '`Post`.`modified`',
'e42609d9744a7d1ce80c8d838b9ea07c' => '`find-this-text`', # <-
'c0a33fa0f04ac4682dcdc4b25167b3a8' => '`Post`'
),
'fields' => array(
'952d56c2bf037c8195bdd5fba57b1024' => array(
(int) 0 => '`Post`.`id`',
(int) 1 => '`Post`.`title`',
(int) 2 => '`Post`.`body`',
(int) 3 => '`Post`.`created`',
(int) 4 => '`Post`.`modified`'
)
)
)
请注意,缓存包含&#34; user&#34; (或开发人员)输入,该数组是写入缓存at the end of a request的内容。
此示例还应突出显示缓存随时间增长的原因 - 缓存依赖于迄今为止发出的查询,随着时间的推移,更多查询排列由应用程序发出,导致方法缓存增长(但通常不会MB)。
对所描述的问题进行了非常简单的修复:禁用方法缓存。
即。将以下内容放在您的应用程序中:
DboSource::$cacheMethods = false;
这当然意味着性能下降,因为不会使用方法缓存,因此每次请求都会发生相对昂贵的基于preg的引用操作。
如果正在使用&#34;模型&#34;的db-instances填充缓存。 - 很可能某处存在应用程序问题。这不正常,它不应该发生,并且完全取决于应用程序正在做什么。鉴于它无法提供具体的解决方案。
但是,如果您可以在包含大量数据的缓存中识别任何特定键,则可以使用它来查找负责的查询。例如:
// anywhere
if (isset(DboSource::$methodCache['name']['e42609d9744a7d1ce80c8d838b9ea07c']) {
// a query with find-this-text has been issued somewhere
}
您可以(暂时)将此类逻辑添加到where the dbo methodCache property is modified,以便能够检测修改&#34;原位&#34;:
public function cacheMethod($method, $key, $value = null) {
if ($this->cacheMethods === false) {
return $value;
}
if (!$this->_methodCacheChange && empty(self::$methodCache)) {
self::$methodCache = Cache::read('method_cache', '_cake_core_');
}
if ($value === null) {
return (isset(self::$methodCache[$method][$key])) ? self::$methodCache[$method][$key] : null;
}
$this->_methodCacheChange = true;
// Added
if ($method === 'name' && $key === 'e42609d9744a7d1ce80c8d838b9ea07c') {
App::uses('Debugger', 'Utility');
$this->log("Query with find-this-text in it issued", "wat-debug");
$this->log(Debugger::trace(), "wat-debug");
}
// Added end
return self::$methodCache[$method][$key] = $value;
}
这将允许您识别直接负责将大量数据注入方法缓存的内容;然后更正应用程序代码,以便可以按设计启用和使用方法缓存。
答案 1 :(得分:1)
使用最新的CakePHP 2旧版本,https://stackoverflow.com/a/23287510/47573提出的修复对我不再有用;该属性不是静态的,因此您不能简单地覆盖其他地方。
我想出的解决方案是创建一个自定义的数据库驱动程序,该驱动程序扩展了我使用的CakePHP中的驱动程序:
app/Plugin/PostgresCustom/Model/Datasource/Database/PostgresCustom.php
Postgres
,而后者又扩展了定义该属性的DboSource
PostgresCustom
类中,我只是通过public $cacheMethods = false;
覆盖了属性app/Config/bootstrap.php
中,我通过CakePlugin::load('PostgresCustom');
注册了插件app/Config/database.php
中,我到处将datasource
的值更改为PostgresCustom.Database/PostgresCustom