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

时间:2014-04-23 09:21:20

标签: php cakephp ubuntu 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)有没有其他可能解决这个问题,以便不断删除这个文件?

2 个答案:

答案 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
  • 该类扩展了Cakes Postgres,而后者又扩展了定义该属性的DboSource
  • 在我的PostgresCustom类中,我只是通过public $cacheMethods = false;覆盖了属性
  • app/Config/bootstrap.php中,我通过CakePlugin::load('PostgresCustom');注册了插件
  • app/Config/database.php中,我到处将datasource的值更改为PostgresCustom.Database/PostgresCustom
  • 利润