Высокая нагрузка сайта написанного на Kohana
Вступление
«A very fast framework. Benchmarking a framework is hard and rarely reflects the real world, but Kohana is very efficient and carefully optimized for real world usage.»
Так написано на главной странице этого фреймворка, так ли это? Да так, но с напильничком. Немного о проблеме.
У меня был заказ от студии creative-cafe.ru на один высоконагруженный проект http://www.jv.ru/longlivers, вроде на девелоперской машине работает хорошо, быстро. Показатели загрузки главной страницы с отколюченными системами кеширования под Ubuntu 11.10 показывают 1-2 секунды (после оптимизации 30-50ms), под виндой вообще караул 4-5 секунд, причём одно и тоже железо, просто ОСи разные, но в этой статье не об этом (советую работать под ОСью приближенной к продакшену). Так вот показатели вроде неплохо 1-2 секунды, а на продакшене сервер то мощнее будет, там вообще летает, но до некоторых действия. Когда заказчик нажал F5 и подержал так секунд 10, сервер смог загрузить контент только через 30 сек… Всего было отправлено около 200-300 запросов… Это уже не порядок, а что если 1000 зайдет?
Конечно о тестировании высокой нагрузки сказать ничего не могу, т.к. не сталкивался с такими тестами, если кто-то что-то знает отпишитесь в комментариях. Естественно я знаю о проблеме и что надо делать, и так начнём.
Инструменты для оптимизации
Первым делом надо позаботиться о БД (структуры, запросы), о кешировании, о сжатии стилей и скриптов.
Оптимизация БД
БД в проекте вообще маленькая 15 таблиц, она полностью сделана по нормализации, поставлены ключи в тех местах которые нужны, оптимизированы все запросы, запросы которые «системные» (об этом позже) закешированы. Всего на главной выполняется 22 запроса после кеширования и занимает это вообще мелочь 2.5 ms.
Для оптимизации таблицы могу порекомендовать юзать функию explain, почитать что такое нормализация таблиц БД и ещё рекомендую настроить и смотреть лог медленных запросов, он будет актуальным когда база наберет инфу и тогда можно смотреть какой запрос превышает порог медленных запросов. Но все это не относится к фреймверкам, это просто понимание работы БД.
Чем же нам может помочь фреймворк? Для работы с БД я использовал ORM, как я мог заметить при работе с разными фреймами, все ОРМы считывают структуры таблицы, что Zend Framework, что Kohana. И так зачем нам каждый раз считывать структуру таблиц, если они крайне редко меняются особенно на продакшене? Для этого надо закешировать эту информацию, ниже приведён класс который позволяет это сделать:
<?php defined('SYSPATH') OR die('No direct access allowed.'); /** * Перекрытие метода получения данных о структуре таблиц * * @package Core * @author Maxim Nagaychenko <maxnag [at] meta.ua> * @copyright Maxim Nagaychenko * @filesource */ class ORM extends Kohana_ORM { /** * Кеширование структуры таблицы * * @see Kohana_ORM::list_columns() * @return array */ public function list_columns() { $cache_lifetime=360000; // 100 часов $cache_key = $this->_table_name ."_structure"; $result = Cache::instance()->get($cache_key); if ($result) { $columns_data = $result; } if( !isset($columns_data)) { $columns_data = $this->_db->list_columns($this->_table_name); Cache::instance()->set($cache_key, $columns_data, $cache_lifetime); } return $columns_data; } }
Данный метод я положил в папку application/classes/orm.php в моделях которые используют наследование от ORM я ничего не менял, т.е.
class Model_Contest extends ORM { .... }
фреймворк ищет сначала «у меня» этот файл и если не найдет, то найдет «у себя» в модуле ORM. И так этим методом я решил проблему лишних запросов. Также, уже в зависимости от проекта, можно данные запросов которых несут статических характер (у меня это разные настройки, мыло аминов, кол-во данных на страницу и тд) также можно закешировать.
Конечно сам ОРМ нагружает систему, т.к. выдает все данные запроса, т.е. select * from, а как сделать если надо только определённые поля? Я не знаю, кто знает подскажите. Особенно это заметно на большой таблице с большим кол-вом полей и забором большого кол-во данных. Тут конечно больше проблем в БД, но всё же ОРМу тяжко. Использовать простые запросы куда менее ресурсоёмко, но увы проигрываем в простоте построения запросов.
Стили и скрипты
Лучше если все стили и скрипты будут сложены в одном файле соот., это сэкономит на кол-ве запросов к серверу, что тоже время. Например я на главной использую 8 файлов-скриптов, 2 файла стилей, отсюда дополнительно 10 запросов на сервер. Как можно с этим бороться? Для этого я использую модуль Minify. У него хорошая документация, легко подключается к системе и выполняет свои функции, кроме «слепки» файлов в один, он еще может удалять комментарии и различные спецсимволы.
Кеширование
Для системы кеширования я выбрал memcache, он позволяет сохранять данные по типу key=>value, хранит их в ОЗУ сервера, соответственно работа с этим типом кеша очень быстрая.
Что я храню в мемкеше? Данные по структуре таблиц, которые требуются для работы с ORM, различные настройки сайта, которые меняются крайне редко, это у меня кол-во записей на странице, для каждого в раздела, контактные данные для отправки писем. Также по всему сайту есть сквозной блок новостей, которые показывает последние две новости проекта, вот такие блоки я и закешировал, при изменении данных новостей, кеш переписывается на новый. На сайте имеются много модальных окон, они построены на основе jQueryUI, а контент (формы, тексты) строятся каждый раз при создании страницы, а как часто люди при просмотре сайта нажимают зайти, зарегистрироваться и тд? Думаю намного реже, чем просто смотрят контекстные страницы, поэтому html этих окон закеширован, что дало тоже большой прирост. Прирост дало то, что контент в эти окна грузятся с БД, а формы строятся с помощью класса Form, что сильно нагружает систему.
Отказаться где можно от использования ООП
Да, это так. Программы разработанные на ООП занимают в памяти куда больше места, чем обычные процедурные, и на больших проектах заметны тормоза. Ниже я привел примеры построения формы на чистом XHTML и с использование класса Form. По своей сути этот класс всего лишь обёртка над тегами формы, можно обойтись и без него, но честно труднее, т.к. валидация, всякие изменения хорошо работают с этим классом. Также есть класс URL которые выдает полный урл, конечно можно без него обойтись, кто мешает в теге ссылки написать относительный урл? Но этот фреймверк, он должен быть универсальным, поэтому исключить этот класс нельзя. В чем же заключается его универсальность? Например сегодня ваш сайт живет по адресу http://example.com, потом вы решили его перенести по пути http://example.com/blog, что же будет без использования класса URL, понадобится все ссылки перебить с / на /blog, а представляете сколько их может быть по всем файлам, также менять роутеры и прочее… беда, а вот с использованием этого класса позволяет всего навсего в файлах bootstrap.php и .haccess изменить урл сайта на нужный вам и все ссылки тут же преобразуются. Тут надо и делать выбор или писать без этого класса, выигрыш в скорости или с ним, но тогда потеря производительности, но универсальность. Думайте сами.
Конкатенация содержимого файлов
При работе сайта по управлением Kohana подключается множество файлов через внутренний автолоадер, только системных файлов порядка 70, остальные сильно зависят от подключённых модулей и достигает до 260 на главной странице сайта. Время которое мой локальный комп подключет эти файлы вообще смешное 5 ms, я бы и не обращал на это внимание, но заказчик попросил объединить это все в один файл и уменьшить кол-во инклюдов… Ну что тут скажешь, он платит.
Нашелся этот модуль у одного блогера, описание и проблема решения тут SuperCache. После его применения кол-во фалов сократилось до 75 c 260.
Инструменты профайлинга
Для отслеживания «узких» мест я использовал различные инструменты. Например мне понравился DebugToolbar, это чисто информационный модуль который показывает все необходимые глобальные переменные со значениями, время выполнения различных частей фреймворка, запросы на странице, какие модули подключены, какие роутеры есть и какой задействован и много другое, это все я указал в примере, внизу страницы, также показывает замеры времени по меткам поставленным с помощью класса Profiler.
Второй инструмент это класс Profiler и он встроен в ядро фреймворка. Как раз с помощью этого класса я смог поставить точки в разных частях сайта и посмотреть какая часть сколько времени отрабатывается. Например интересует сколько времени занимает прорисовка формы, берем ставим точку запуска в начале формы и в конце точку остановки. Профайлер нам выдаст сколько времени это заняло, как раз это и мне помогла найти «узкие» места. Как работать с профайлером опишу в другой статье.
Примеры
Я тут приведу всего один пример, который покажет 2 одинаковых формы (просто прорисовка без логики работы). В самом низу формы как раз расположен профайлер, в нём есть раздел «Построение формы» и в нем два пункта, как можно убедится результаты ощутимы — построение на чистом html в тысячи раз быстрее чем строить тоже самое на ООП, особенно если представить это в рамках большого проекта. Обратите внимание еще на кол-во используемой памяти.
Также в верхнем правом углу расположен DebugToolbar, там тоже есть нужная инфа для работы.
PS Нужны скидки на товары или услуги? Приобретайте купоны на www.newsavings.ca, которые помогут Вам сэкономить ваши средства.
Статья просмотренна 720752 раз, зашло посетителей 74713