3

我正在使用 cake 2.1.3,目前有一个页面每秒获得数百次查看,因此我使用缓存以更好地处理负载。问题是,一旦缓存过期,我的服务器资源以及数百个 mysql 连接都会激增。

我想知道我是否以错误的方式进行此操作,是否应该运行 cron 来缓存页面而不是我当前的操作方式,或者是否还有其他我没有想到的技术。

这是我的功能在我的控制器中的样子:

public function index() {
    $this->layout = 'ajax';

    if (isset($this->params['url']['callback'])) {
        $callback =  $this->params['url']['callback'];
    }else{
        $callback = 'callback';
    }
    $this->set('callback',$callback);

    $today = date("Y-m-d");
    $end_date = strtotime ('+1 day' , strtotime($today)) ;        
    $end_date = date ( 'Y-m-d' , $end_date);

    $start_date = strtotime ('-1 day' , strtotime($today)) ;
    $start_date = date ( 'Y-m-d' , $start_date);

    $total = Cache::read('popular_stories', 'short');
    if (!$total) {
        $total = $this->TrackStoryView->find('all', array(
           'fields' => array('COUNT(story_id) AS theCount', 'headline', 'url'), 
           'conditions' => array('date BETWEEN ? AND ?' => array($start_date,$end_date)),
           'group' => 'story_id',
           'order' => array('theCount DESC'),
           'limit' => 20,
        ));
        Cache::write('popular_stories', $total, 'short');
    }

    $this->set('story', $total);    
}

这是我的缓存配置在我的 bootstrap.php 文件中的样子:

Cache::config('short', array(
    'engine' => 'File',
    'duration' => '+60 minutes',
    'path' => CACHE,
    'prefix' => 'cake_short_'
));

这是我的视图文件中的内容:

<?php echo $callback . '('.json_encode($story).')'; ?>

我希望一旦缓存文件过期,一旦第一个人访问它,它就会创建一个新的缓存文件并为每个人提供服务,但是因为每秒有数百人在访问它,所以这种方法似乎是'不适合我,也许我应该以某种方式将视图视图缓存为 cron,或者可能有一种不同的缓存方式,我没有使用。

4

3 回答 3

4

TLDR:强迫用户为你打破缓存并不理想。使用计时作业或数据更改触发器。

解释: “每秒数百次查看”是问题所在。当它过期时,在它试图创建缓存文件期间有“数百个视图”。

第一个人点击它,它开始创建缓存,与此同时,另外一百多人点击它,它看起来,还找不到缓存文件......等等。

如果可以管理,请尝试在更新项目时手动创建缓存,或者运行一个 chron 作业,每 X 分钟创建一个新缓存,而不是让它为用户创建。

Cake 有很多很酷的触发器afterSave(),你可以用它们来触发这种事情。但是,如果这对您的情况没有意义,那么计时工作对您来说应该没问题。

于 2013-03-11T15:07:58.560 回答
4

听起来您或多或少地找到了答案(自动创建缓存,而不是由用户请求触发)。

要做到这一点,请查看 cake 的 AppShell 类,这本书在这里谈到了它。然后,您可以将其链接到 cron 作业。如果您通过 thru 创建文件Cache::write,cake 应该知道它是一个新的缓存文件并透明地读取它。您可能希望保留“如果找不到缓存”块,以防您的 cronjob 失败。

cake 中的 Shells & Tasks 很有趣,可以让您将应用程序从专门使用请求/响应模型中解放出来。

于 2013-03-11T15:18:12.877 回答
2

我认为答案在于计算出这个查询需要多长时间:

$total = $this->TrackStoryView->find('all', array(
           'fields' => array('COUNT(story_id) AS theCount', 'headline', 'url'), 
           'conditions' => array('date BETWEEN ? AND ?' => array($start_date,$end_date)),
           'group' => 'story_id',
           'order' => array('theCount DESC'),
           'limit' => 20,
        ));

假设它需要 500 毫秒。

您每秒获得 100 次点击,因此当缓存清除第一个请求时会发出 find 调用,然后 50 个其他人也在第一个请求完成之前发出 find 调用。

一种替代解决方案:

使缓存的内容永不过期。通过调用运行的不同操作来设置覆盖缓存的 cron 任务:

Cache::write('popular_stories', $total, 'short');

覆盖缓存的内容。

这样,每秒 100 个用户将始终从缓存中读取

于 2013-03-11T15:10:16.680 回答