为什么CakePHPs cake_core_method_cache文件会随着时间的推移而变大?

Joh*_* N. 6 php ubuntu cakephp cakephp-2.4

我们有一个很大的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)有没有其他可能解决这个问题,以便不断删除这个文件?

AD7*_*six 5

这个缓存是如何使用的

CakePHP 中对 method_cache 的唯一引用位于Dbo Source中。这是一个在整个类中广泛使用的缓存,用于缓存(相对)昂贵的引用操作的结果,或者如相关文档块所示:

缓存查询解析操作的结果。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);
    }

}
Run Code Online (Sandbox Code Playgroud)

运行它会产生以下输出:

> 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`'
        )
    )
)
Run Code Online (Sandbox Code Playgroud)

请注意,缓存包含“用户”(或开发人员)输入,该数组是在请求结束时写入缓存的内容。

此示例还应强调为什么缓存随时间增长 - 缓存取决于迄今为止发出的查询,并且随着时间的推移,应用程序发出更多查询排列,导致方法缓存增长(但通常不会增长很多 MB)。

轻松修复

对于所描述的问题有一个非常简单的修复方法:禁用方法缓存。

即,将以下内容放在应用程序中的任何位置:

DboSource::$cacheMethods = false;
Run Code Online (Sandbox Code Playgroud)

这当然意味着性能下降,因为不会使用方法缓存,因此每个请求都会发生相对昂贵的基于 preg 的引用操作。

更好地修复

如果缓存中充满了“模型的数据库实例” - 很可能某个地方存在应用程序问题。这是不正常的,不应该发生,并且具体取决于应用程序正在执行的操作。鉴于不可能给出具体的解决方案。

但是,如果您可以识别缓存中包含大量数据的任何特定键,则可以使用它来查找负责的查询。例如:

// anywhere
if (isset(DboSource::$methodCache['name']['e42609d9744a7d1ce80c8d838b9ea07c']) {
    // a query with find-this-text has been issued somewhere
}
    
Run Code Online (Sandbox Code Playgroud)

您可以(暂时)将这种逻辑添加到修改 dbo methodCache 属性的位置,以便能够“原位”检测修改:

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;
}
Run Code Online (Sandbox Code Playgroud)

这将使您能够识别直接负责将大量数据注入方法缓存的因素;然后更正应用程序代码,以便可以按设计启用和使用方法缓存。