Мы специально провели почти неделю издеваясь (в буквальном смысле) над импортом, Zoo и сервером, чтобы найти узкие места в производительности и узнать сможет ли JBZoo работать с большим объемов материалов.
Почему JBZoo может тормозить при больших объемах?
- Во-первых, изначально Zoo и JBZoo не были предусмотрены под большие нагрузки и объемы, в основном из-за самого Zoo и структурой базы данных Zoo. Разработчики Zoo (YOOtheme) сами наверное не рассчитывали, что подобные объемы будут использоваться на их платформе. Но, у нас есть пару вариантов, которые смогут помочь при работе с большими объемами.
- Во вторых, чудес не бывает и производительность не берется из неоткуда.
- В третьих, сотни тысяч материалов - это реально очень много. Пожалуйста, не утверждайте обратное без серьезных обоснований.
- Будьте реалистами а не сказочниками
Некоторые из решений ниже, при определенных условиях, можно использовать на обычных сайтах. Только не нужно слепо все копировать - сломаете сайт! Думаем…
и бекапимся...
Условия тестирования
Сначала определимся, что мы подразумеваем под “большим объемом” ?
- Если количество материалов превосходит 100 000.
- Количество категорий для этих(!) материалов от 500 и выше. Тут большую роль играет количество взаимосвязей между категориями и материалами.
Сервер у нас отдельный, “железный” и полностью наш - FastVPS (EX-4)
- Процессор: 8 ядер, 3,4Гц, Intel
- Память: 16 GB
- HDD: RAID, почти 3000 Gb
- Тест произв-ти JBZoo (116 попугаев): http://llfl.ru/d6uoj
Софт
- Debian 7
- Apache 2.4 + Nginx 1.0
- MySQL 5.5
- PHP 5.4 + xCache 2.x
- Joomla: 3.3.1
- JBZoo: 2.1.4 Pro
- Zoo: 3.1.6
Сразу же оговорюсь. Сервер наш - это далеко не обычная VPS-ка и тестировали на нем из соображений:
Серьезный сервер = Серьезный сайт + Серьезные объемы
Если вы решили на виртуальном хостинге в 300-500 рублей делать что-то подобное, то я могу только слезами на глазах пожелать вам лишь... “удачи”
К слову, VPS за 500 рублей будет по определению медленнее, чем шаред за те же деньги.
Импорт 300к+ материалов и 500 категорий
Мы тестировали следующий вариант контента
- Всего порядка 320 000 материалов
- Примерно 510 категорий
- Примерно у 30 000 материалов привязка к 10 категорий одновременно. Остальные материалы - только 1 категория.
- В типе материала - 9 текстовых элементов (Text) и элемент цены (JBPriceAdvance).
- У элементов разные значения - числовые, строковые и дата.
- Уникальность простых повторяемых значений элементов в пределах 30 штук.
- В каждом сотом материале элементы повторяемые, примерно 4.
- Размер импортируемого файла примерно 74мб.
- Категории создавались “на лету”.
Условия тестирования скорости импорта
- 100 000 разных материалов.
- Файл примерно 74 мегабайта.
- Шаг импорта - 100 материалов за раз (т.е 1 000 шагов).
- Без оптимизации - Чуть больше полутора часов.
- Со всеми оптимизациями (ниже) - примерно 50 минут
Дополнительные тесты показали, что размер файла большой роли не играет. Выигрыш (или проигрыш) “смазывается” когда дело идет к концу. Я грузил одним большим, чтобы не отрываться от чая.
Несколько ускоряет манипуляция с размером шага. Тут все зависит от ваших данных. Только экспериментами можно найти истину… У нас это было 100 за раз.
Как выглядит база после импорта?
* особое внимание стоит обратите на выделенные колонки
Способы разгона импорта
Помним! Код, который мы будем удалять, написан там не от хорошей жизни, потому что программисты скучали. Комментирование кода сказывается на функционале вашей системы!
Убираем проверку алиаса на уникальность
(Только если вы уверены в уникальности алиасов в csv файле!)
Файл - /administrator/components/com_zoo/tables/item.php метод save()
Комментируем следующие участки кода.
// Проверка уникальности if ($this->app->alias->item->checkAliasExists($object->alias, $object->id)) { throw new ItemTableException('Alias already exists, please choose a unique alias'); }
Файл - media\zoo\applications\jbuniversal\framework\helpers\jbimport.php
примерно на 382 строке комментируем
$item = $this->_checkItemAlias($item);
Последствие: Фатальная ошибка при совпадении alias’ов. Придется перезапускать импорт.
Отключаем индекс Zoo
Файл - /administrator/components/com_zoo/tables/item.php метод save()
//Zoo index foreach ($object->getElements() as $id => $element) { // get search data if ($data = $element->getSearchData()) { $search_data[] = "(".$object->id.", ".$db->quote($id).", ".$db->quote($data).")"; } } // delete old search data $query = "DELETE FROM ".ZOO_TABLE_SEARCH ." WHERE item_id = ".(int) $object->id; $db->query($query); // insert new search data if (count($search_data)) { $query = "INSERT INTO ".ZOO_TABLE_SEARCH ." VALUES ".implode(", ", $search_data); $db->query($query); }
Последствие: Теряется возможность поиска фильтра по textarea и стандартного поиска Joomla.
Отказываемся от индекса JBZoo во время импорта
Файл - /media/zoo/applications/jbuniversal/framework/events/jbevent.item.php метод saved()
Комментируем весь код
// vars $app = self::app(); $item = $event->getSubject(); $itemType = $item->getType()->id; // hack for JBZoo import optimization if ($item->getParams()->get('jbzoo.no_index', 0) == 1) { return null; } // update index data $app->jbtables->checkSku(true); $indexTableName = $app->jbtables->getIndexTable($itemType); if ($app->jbtables->isTableExists($indexTableName, true)) { JBModelSearchindex::model()->updateByItem($item); }
Последствие: Сохранение и редактирование материалов не будет наполнять индекс. Придется после импорта (и любых изменений материалов) запускать переиндексацию вручную.
Играемся с шагом импорта
Файл media\zoo\applications\jbuniversal\framework\helpers\jbimport.php константа
STEP_SIZE = 50
Попробуйте ее увеличить до 100-200. Очень большие значения сделают только хуже. Все зависит от "однородности" ваших данных параметров вашего сервера.
Оптимизация JBZoo Некоторые советы
- Нет никакого смысла импортировать большие объемы под windows. Проблемы NTFS и мелких файлов PHP “съедят” ваш сайт при любом процессоре и даже на SSD дисках.
- Как показали результаты тестов, при большом количестве импортируемой информации, переиндексация пройдет быстрее отдельным процессом после создания материалов.
- От модуля JBZoo Search List по возможности лучше отказаться т.к он использует наиболее тяжелые запросы в базу для такого количества.
- Отключаем все лишние плагины Joomla. Особенно плагины finder и search. Они генерируют дополнительную нагрузку на базу и сайт в целом.
- В фильтре меньше использовать элементы с уникальными значениями - radio, select и т.д.
- Используйте точный поиск. Полнотекстовый очень требовательный по определению.
- НЕ используйте множественные сортировки. Сортировка - это всегда тяжелая операция.
- НЕ используйте сортировку от Zoo (она кривая, особенно алфавитная)
- НЕ используйте альфаиндекс (поиск по букве и выборка уникальный букв для блока - очень тяжелые операции)
Ускорение сайта
- Обязательно включаем кеширование (для JBZoo большой разницы нет между стастический и динамический)
- Желательно НЕ использовать файловый кеш. Хорошо справляется модуль php memcache.
- Если у вас статический контент, то можно включить плагин кеширования. Он полностью сохраняет html страницы. Осторожно плагин никак не проверяет, обновились ли данные.
- Если вам не важны данные о начале и окончании публикации материала, можно изменить sql запрос. На 100 000 материалов это помогло выиграть ~5 секунд из 17
Изменить запрос необходимо для категории в самом Zoo и в JBZoo
1. Файл - administrator\components\com_zoo\tables\item.php . Метод getByCategory.
Удаляем из него следующие строки
." AND a.".$this->app->user->getDBAccessString($user) ." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")" ." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
2. Файл - media\zoo\applications\jbuniversal\framework\models\jbmodel.php . Метод _getItemSelect
Избавляемся от кода
->where('tItem.' . $this->app->user->getDBAccessString()) ->where('(tItem.publish_up = ' . $this->_dbNull . ' OR tItem.publish_up <= ' . $this->_dbNow . ')') ->where('(tItem.publish_down = ' . $this->_dbNull . ' OR tItem.publish_down >= ' . $this->_dbNow . ')')
Еще полезная информация о базе и фильтре от SmetDenis ...
Источник http://forum.jbzoo.c...udet-bystree-e/
- Скорость работы фильтра не зависит от настройки тизеров. Как понимаю, скорость фильтра - это непосредственно скорость поиска, т.е сопутствующих запросов в БД. Не путайте с выводом результата и генерацией HTML
- Если у вас одновременно на странице выводится несколько десятков (а то и сотен) тизеров, тогда конечно, вывести данные напрямую из объекта материала будет быстрее, минуя проверку полей на доступ и рендеры шаблонов самих элементов. Тут можно выиграть только если используются заведомо сложные элементы (цена, каскадные селекты например), где нужно не просто вывести значение, а еще вычислить что-нибудь или показать виджет.
- Если говорить о поиске, то опять же зависит от того, по каким полям вы ищите, какой поиск и какого рода данные там хранятся. Лучше смотреть на конкретные примеры. Однозначно нельзя сказать. Запросы в базу собираются динамически + умеют частично и эффективно кешироваться на уровне MySQL.
Вот несколько мыслей по поводу фильтров
- Фильтр оперативнее ищет по числам, т.е оптимизация на уровне MySQL. На втором месте будут даты и самый медленный - это текст.
- Точный поиск всегда работает в разы быстрее полнотекстового (учите SQL).
- Поиск по textarea - самый медленный (причин много, основы программирования).
- Если вы ищите по категориям и у вас используется множественная привязка одного материал ко многих (и таких привязок оооочень много), то это снижает скорость. Например, у нас 100 категорий и 2000 материалов. Максимально привязано все ко всему. Получается, что 2000 * 100 ~ 200 000 будет участвовать в запросе. Но я лично не представляю логическое обоснование таким сайтам =)
- 300 категорий - это много только для человека. MySQL легко орудует десятками тысячами записей. Для него это рутина и бытовуха =).
- Множественные поля конечно усложняют поиск, но не критично. Конечно если у вас на одно поле не приходится 10+ значений и подобных полей в материале 5-10. Т.е получается что на 1 материал индекс будет хранить как минимум 10 и более записей.
- Большое количество полей в одном типе материала проявит себя только после ~20-30 штук (считаю только те, которые содержат полезные(!) данные для поиска). Просто в этом случае можно упереться в некоторые ограничения MySQL. Не критично и зависит от пунктов выше.
- Количество приложений и типов сильной роли не играет, т.к на уровне базы данных типы имеют физически разные таблицы, а каталоги - это простейшее индексируемое поле.
- … ищите хороший хостинг (в JBZoo есть система тестирования скорости)
---
В силу невероятно тупых (нет других слов) мнений о базах данных, их размерах и кол-ве запросов в популярных очерках незадачливых, не побоюсь этого слова, "web-мастеров" - у людей складываются не правильные понятия о принципе работы сайта в целом.
Сразу вспоминаю мой Joomla-Book.ru, главная страницы. ArtioSEF добавляет 250 запросов. И че?)) Летает =)
Скажу вам как человек, который делал даже такие вещи как автодополнение на лету по 8 миллионной базе весом в 35Гб. Все зависит от конкретного запроса и индексов в базе. Можно сделать 300 запросов, при этом сайт будет грузится 0,5 сек или 10 запросов в туже самую базу за теми же данными, но уже все будет грузится в 10 раз дольше.
Поэтому лучше рассматривать конкретные примеры, конкретный хостинг, конкретные данные.
В заключение от автора
Работу Zoo и JBZoo проверили на 320 тысячах материалах и 500 категориях.
До оптимизации загрузка страницы категории длилась ~17 секунд - 20 материалов на странице, у каждого по 10 элементов + заведомо тяжелые модули.
После всех выше описанных оптимизаций скорость загрузки категории увеличилась до ~3 секунд, из которых 2 занял рендеринг шаблона (Список материалов), ~0.5 секунд на вывод JBZoo Module search(Очень много опций), ~0,5 секунды для модуля JBZoo Module Search List.
Это только базовая оптимизация (а ускорение уже в 6 раз), дальше нужно смотреть каждый сайт индивидуально.
Оперативной памяти понадобилось 90мб (очень много HTML и Zoo начинает течь по памяти, причину не искали).
Сами видите, какие потребовались ресурсы и силы, что бы при больших объемах работоспособность сайта сохранилась.
Согласитесь, не каждый дешевый хостинг может себе это позволить.
Если вы решили делать сайт на JBZoo под большие объемы информации приготовьтесь раскошелиться на хороший сервер, хотя, это обязательное условие для нормальной работы сайта.
Считаю, что JBZoo вполне справилось с объемом 100к+ и уж тем более справится с типичными 3000 из магазина.
Главное - не отключайте голову
PS С нетерпением жду ваших комментов, замечаний и наблюдений. Открыт для срача холивара.
patch.zip 20.18KB 382 downloads
- administrator\components\com_zoo\tables\item.php - убрана индексация зуу, проверка alias на уникальность, проверка по диапазону дат, доступу пользователя.
- components\com_zoo\controllers\default.php - отключаем подсчет количества материалов для категорий. Бережем оперативную память.
- media\zoo\applications\jbuniversal\framework\events\jbevent.item.php - выключаем индексацию зуу.
- media\zoo\applications\jbuniversal\framework\helpers\jbimport.php - убираем проверка alias на уникальность.
- media\zoo\applications\jbuniversal\framework\models\jbmodel.php - Изменяем sql запрос. Нет проверка по диапазону дат, доступу пользователя.
Edited by tapakan, 07 July 2014 - 10:01.