Кэшируй, кэшируй, кэшируй запрос назло буржуазной Европе!

Предыстория этого вопроса такова: одно время магаз на ShopScript работал у меня на довольно хилом VDS и посещения поисковых ботов практически клали сервер на обе лопатки. Типичная, так сказать, DDOS атака :-) Поэтому я озаботился производительностью самого скрипта. Предпринял следующие логичные, как мне кажется, шаги:

  1. Добавил недостающие индексы в разные таблицы с товаром, параметрами товара, категории, валюты и т.д.
  2. Убрал подсчет запросов категорий и товаров. Во-первых это оказалась бесполезная фича, во-вторых это было просто.
  3. Закэшировал несколько запросов.

Эти три пункта помогли решить проблему. Не знаю, какой оказал бОльшее влияние, но первого точно было недостаточно.

Объяснять как установить PEAR, добавить в include_path путь до него не буду.

Первый вариант кэширования я сделал с помощью класса Cache_Lite из PEAR. В общем-то можно было бы обойтись и просто сохранением в файл, но мне не улыбалось писать код для сравнения даты создания файла, вычисления устаревания кэша и т.д. – все это уже сделано, зачем мне писать то же самое?

Что бы нам такого закэшировать? Посмотрим код ShopScript’a. Ух-ты! Есть вот такой перл в самом index.php:

Загружаются подряд все категории товаров! Когда это 5-10 категорий – не очень страшно. Если общее количество категорий приближается к сотне, да еще есть описания, то общий объем данных получается очень приличным. Да еще этот код срабатывает при каждом запуске скрипта, нужен-не нужен – пофиг.

Категории меняются редко, поэтому вполне достаточно выполнять такой запрос, скажем, раз в сутки. Вот этим и займемся.

Создадим директорию cache и разрешим скрипту туда запись. Если директория в корне сайта, лучше в нее добавить файлик .htaccess со строчкой ‘Deny from all’.

В начало index.php добавим подключение класса Cache_Lite и создание экземпляра класса. У меня получилось вот так:

В переменной $cache_categories_id – метка, по которой будет извлекаться данные из кэша. В общем, доку по Cache_Lite надо хотя-бы просто просмотреть.

А код, где делается запрос к БД на выборку изменим на такой:

Вот и все. Еще в том же index.php есть запрос на выборку всех валют – тоже хороший кандидат на кэширование.

Еще можно внимательно рассмотреть запросы при выводе информации о товаре (includes/produc_detailed.php) и подумать о том, что информацию о товаре тоже можно кэшировать. Но в случае изменения неплохо бы и сбрасывать кэш.

Схема с PEAR::Cache_Lite прожила довольно долго. VDS я сменил на другой, у которого памяти побольше было и это позволило установить кэшер байткода XCache. А некоторое время назад я обнаружил, что ZendFramework научился работать с этим самым XCache. И я переделал работу с Cache_Lite на Zend_Cache с бэкендом XCache. Теперь переменные хранятся вообще в памяти.

Автор

Сергей Родовниченко

Родился, учился, работал и все такое. Занимаюсь поддержкой сайтов на Shop-Script, Joomla, Wordpress, Prestashop. А также на самописных движках на базе CakePHP.

21 thoughts on “Кэшируй, кэшируй, кэшируй запрос назло буржуазной Европе!”

  1. На офф форуме ответов не дождешся ((( Скажите, а данный «хак» для WebAsyst ShopScript применим? И так же про отключение статистики просмотра?
    Спасибо!

  2. На офф форуме ответов не дождешся ((( Скажите, а данный «хак» для WebAsyst ShopScript применим? И так же про отключение статистики просмотра?
    Спасибо!

  3. Про WASS не в курсе. Я ее сейчас не использую и пока проектов на ней не планируется. :-/

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

  4. Про WASS не в курсе. Я ее сейчас не использую и пока проектов на ней не планируется. :-/

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

  5. Да, по аналогии сделал, вроде счетчики встали…
    sitepublishedSChtmlscriptsincludescategory.php
    и
    sitepublishedSChtmlscriptsmodulesproductsscriptsproduct_detailed.php

  6. Да, по аналогии сделал, вроде счетчики встали…
    site\published\SC\html\scripts\includes\category.php
    и
    site\published\SC\html\scripts\modules\products\scripts\product_detailed.php

  7. Скажи пожалуйста а можно поподробнее про
    «я переделал работу с Cache_Lite на Zend_Cache с бэкендом XCache. Теперь переменные хранятся вообще в памяти. »
    поподробнее хочется если и кэшировать так чтоб в оперативке все было, заранее большое спасибо

  8. Скажи пожалуйста а можно поподробнее про
    «я переделал работу с Cache_Lite на Zend_Cache с бэкендом XCache. Теперь переменные хранятся вообще в памяти. »
    поподробнее хочется если и кэшировать так чтоб в оперативке все было, заранее большое спасибо

  9. @Den:

    1. Нужно, чтобы на серверы была уставлена система кэширования, типа Memcached (http://www.danga.com/memcached/) или XCache (http://xcache.lighttpd.net/). Если у Вас виртуальный хостинг, придется договариваться с админами, если сервер свой — устанавливать самому.

    2. Скачиваем ZendFramework. http://framework.zend.com/

    3. Заменяем подключение Cache_Lite на Zend_Cache, огладываясь на документацию: http://framework.zend.com/manual/ru/zend.cache.html

  10. @Den:

    1. Нужно, чтобы на серверы была уставлена система кэширования, типа Memcached (http://www.danga.com/memcached/) или XCache (http://xcache.lighttpd.net/). Если у Вас виртуальный хостинг, придется договариваться с админами, если сервер свой — устанавливать самому.

    2. Скачиваем ZendFramework. http://framework.zend.com/

    3. Заменяем подключение Cache_Lite на Zend_Cache, огладываясь на документацию: http://framework.zend.com/manual/ru/zend.cache.html

  11. 0 ORDER BY sort_order, name») or die (db_error());
    while ($row = db_fetch_row($q))
    {
    $cats[$i++] = $row;
    }
    $CacheLite->save($cats, $cache_categories_id);
    }

  12. У меня на сервере установлен XCache. Выглядит это примерно вот так (переменная $CacheLite — наследние от Cache::Lite):

    require_once(‘Zend/Cache.php’);
    $cache_backend_opts = array(‘user’=>’xxxxx’, ‘password’=>’xxx’);
    $cache_frontend_opts = array(‘lifetime’=>43200, ‘automatic_serialization’=>true);
    $CacheLite = Zend_Cache::factory(‘Core’, ‘Xcache’, $cache_frontend_opts, $cache_backend_opts);

    if (!$cats = $CacheLite->load($cache_categories_id))
    {
    $cats = array();
    $i=0;
    $q = db_query(«SELECT categoryID, name, parent, products_count, description, picture FROM «.
    CATEGORIES_TABLE.» where categoryID<>0 ORDER BY sort_order, name») or die (db_error());
    while ($row = db_fetch_row($q))
    {
    $cats[$i++] = $row;
    }
    $CacheLite->save($cats, $cache_categories_id);
    }

  13. А может подскажите, как еще кешировать каждый товар, в частности brief_description? Тоесть перечень коротких описаний при выводе в категории.
    Заранее благодарен.

    1. Отдельное поле не имеет смысл кэшировать. Там довольно мутная функция на выборку списка товаров, надо ее ковырять, но вряд-ли что-нибудь получится. Потому что товары для списка выбираются одним запросом, смотреть кто из них есть в кэше — себе дороже.

  14. А может подскажите, как еще кешировать каждый товар, в частности brief_description? Тоесть перечень коротких описаний при выводе в категории.
    Заранее благодарен.

    1. Отдельное поле не имеет смысл кэшировать. Там довольно мутная функция на выборку списка товаров, надо ее ковырять, но вряд-ли что-нибудь получится. Потому что товары для списка выбираются одним запросом, смотреть кто из них есть в кэше — себе дороже.

  15. жаль. Спасибо.
    А может подскажите что еще можно поковырять для ускорения Премиума? может что еще можно покешировать? смотрю джумла на порядок быстрее работает, вот и пытаюсь у себя как-то оптимизировать без смены движка..

  16. жаль. Спасибо.
    А может подскажите что еще можно поковырять для ускорения Премиума? может что еще можно покешировать? смотрю джумла на порядок быстрее работает, вот и пытаюсь у себя как-то оптимизировать без смены движка..

  17. Уведомление: Форум WebAssist | SergeRod.Me

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *