Кэширование SQL-запросов с Zend_Cache.


    Из всех возможностей компонента Zend_Cache, предоставленных разработчиками фреймворка, я применял на практике в том числе и на этом сайте, только кэширование запросов к базе данных. Статистику запросов можно посмотреть в левом нижнем углу. Если на этой странице никого не было в течении получаса, при первой загрузке будет много запросов. На страницах категорий и рубрик сайта, в т.ч. и на главной, кэшируется все! и в лучшем случае не приходится даже подключаться к базе.

    Что такое фронтэнд и бэкэнд своими словами или теория кэширования light.


    Frontend - это средство хранения данных, которое позволяет получать их в разы быстрее, чем из другого хранилица. То самое другое хранилище и есть backend. К бэкэнду мы стараемся обращаться редко, только когда в этом есть необходимость, потомучто он тяжелый. Фронтэнд мы даем на разтерзание сотням и тысячам пользователей.
    Короче бэкэндом можно считать БД, она у меня на другом сервере и туда не очень хочется постоянно слать запросы. Поэтому я записываю результат запроса в файл и при следующих вызовах скрипта, получаю информацию из него. Пока не пройдет заданное мной время - 30 минут, информация в файле считается актуальной. Или же приходится принудительно делать ее неактуальной, если обновились данные в базе.
    Таким образом за эти пол часа пришли 5-6 пользователей и я сэкономил их время на 0.5 - 0.3 сек. и пожалел сервера (хоть они и американские), а вдруг когда нибудь придет 500-600 человек...

    Хэлпер который инстанцирует объект.


    Сначала был хэлпер, чтобы каждый раз настройки кэша брались из конфигов и это происходило в одном месте. Хелпер только создает объект как нам нужно и возвращает его для работы, так что этот момент можно реализовывать как угодно. У меня он выглядит таким образом:


<?php

require_once 'Zend/Controller/Action/Helper/Abstract.php';

class My_Helper_Action_Cache extends Zend_Controller_Action_Helper_Abstract
{
    
    protected $cache;
    public $config;
    
    // Это происходит единожды, при первом вызове хэлпера
    public function __construct()
    {
        $this->config = new Zend_Config_Ini('/some/path/config.ini', 'cache');
    }
     
    // При прямом вызове хэлпера у меня ничего не происходит
    public function direct()
    {
        
    }

    /** 
     *  @var int
     *  @return obj Zend_Cache */
    public function getCoreCache($life_time = null)
    {
        //Если $life_time не передана, то берем из конфига
        if(!$life_time) $life_time = $this->config->life_time;

        /* Если объект кэша еще не вызывался или нужно создать аналогичный объект, но с другими настройками
             создаем! */
        if (!$this->cache || $life_time != $this->cache->getOption('lifetime')) {
            require_once 'Zend/Cache.php';
            $front_opt = array(
               // Вообще кэшировать ли? Полезно для отладки добавлять такую опцию в настройки
               'caching' => $this->config->caching,
               'lifetime' => $life_time,
               /* Сериализует автоматически объекты и масивы перед записью в файл
                    вообще это работает медленней, но так гораздо удобнее */
               'automatic_serialization' => true
            );
            $back_opt = array(
                'cache_dir' => '/some/path//cache/',
                // Вот тут нужно поэкспериментировать...
                /** 'read_control_type' => 'adler32', @todo */
                // Тут тоже
                'hashed_directory_level' => '1',
                // Права доступа к создаваемым файлам
                'hashed_directory_umask' => '0766'
            );
            $this->cache = Zend_Cache::factory('Core', 'File', $front_opt, $back_opt);
        }

        return $this->cache;
    }
    
}


    Работа в контроллере и метки.



// Получить объект
$cache = $this->_helper->cache->getCoreCache();

// Если данные не закэшированы или истекло время
if (!$posts = $cache->load("zf_posts")) {
    $posts = // запрашиваем из БД что нам нужно
    // Закэшировать, как это просто!
    $cache->save($posts, "zf_posts");
}

// Независимо от того как эти данные оказались в переменной, мы работаем с ними одинаково например:
print_r($posts);
 
    Единственное, что хочется добавить к комментариям: zf_posts это метка, для того чтобы знать какие данные достать из каши фронтэнда. Все записываемое в кэш должно иметь уникальную метку, в противном случае данные перезатрутся и будут косяки.


    Очистка кэша


    Следующее что случится, это наступит момент, когда из кэша нужно что-то удалить. Делается так же просто как и записывается:


$cache = $this->_helper->cache->getCoreCache();
$cache->remove("zf_posts");

    Самое главное следить за моментами, когда необходимо его очищать тут разработчики ZF не помогут. В основном это приходится делать только после редактирования или удаления.

    Тэги.


    Так же есть очень хороший способ группировать данные во фронтэнде используя тэги. Как я уже говорил данные должны иметь уникальную метку и если добавился комментарий к посту, нужно стереть из кэша все комментарии к посту (если хранились "пачкой"), и сам пост т.к. в нем содержится информация о колличестве комментариев, а оно изменилось.
    Две единицы данных (пост и комментарии к нему), хранятся под разными метками и придется выполнить две операции удаления. Этого бы не случилось если бы изначально все делалось так:


$cache->save("post_12", array("post12"));
$cache->save("post_12_comments", array("post12"));

    Сохранили данные под двумя разными метками, но с одним тэгом, и теперь удалить можно одной операцией, вместо 2-х 3-х 4-х и т.д.


$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('post12'));

    Это все что я вычитал в мануале и попробовал на практике. Может что-то еще добавлю. Надеюсь вам будет от этого польза. Так же буду рад увидеть отзывы, критику и все такое.



Добавлена: 17-04-2009 | Пользователем: djaarf | Просмотров: 1783

Комментарии

djaarf 27-04-2009 01:33
Спасибо Анжелика. А Вам успехов в вашем начинании!
Анжелика 27-04-2009 00:29
Здравствуйте, djaarf. Спасибо Вам за статьи. Я еще только учусь использовать данный framework и считаю Ваши статьи очень полезными. Продолжайте свой нелегкий труд и успехов Вам!


Оставить комментарий



Капча *

Captcha

Комментарий будет опубликован после проверки модератором

Для подсветки синтаксиса исходный код следует обрамлять следующими тэгами
<pre><code class="синтаксис" >код</code></pre>
Подерживаются следующие: cpp php javascript sql html-xml css ini