С недавних пор работаю в хостинге MouseDC.ru. И за это время получил несколько жалоб на "медленный сервер". В 100% случаев проблема была связана с CMS. Поэтому решил начать рубрику по тегу CMS. В этой статье взглянем на подводные камни системы управления магазином CS-Cart.
Клиент сделал магазин на CS-Cart. Проект предполагался большой, но клиент выбрал виртуальный хостинг, а не отдельный сервер. Чем больше клиент работал над настройкой сайта, тем больше я замечал аномалий. Сайт клиента генерировал больше 50% обращений к базе MySQL. И это не смотря на то, что на сервере находится 100 сайтов!
Конечно, для хостинга такая нагрузка - это неприятно, но не критично. Первые месяцы жизни сайта владелец загрузил на него только 1 000 товаров. Это достаточно много для интернет магазина. Но просадок в скорости не возникало - клиентские ограничения на сервере ещё были далеко. Но затем владелец сайта загрузил на него 20 тысяч товаров. И сайт начал набирать популярность. Достаточно будет сказать, что поисковый бот от Google сканирует сайты со скоростью ~1 запрос в секунду. Поэтому для сканирования 20 тысяч страниц понадобится ~6 часов. А если учесть, что помимо Google есть ещё Яндекс и тысячи других поисковых систем, ботов и краулеров, то сайт всегда был под нагрузкой.
Отсутствует кеширование в CS-Cart
Обычно сайт легко выдерживает 1 запрос в секунду. К примеру, этот блог. Даже если 100 человек откроют одну и ту же его страницу, то этот сайт продолжит работу. Потому что на этом сайте используется система кеширования, которая минимизирует работу сервера. А именно снижает количество запросов к базе данных. К примеру, у одной из самых требовательных CMS, 1С-Битрикс, без кеширования может быть 20-50 запросов к базе данных на странице. А если включить кеширование, то это значение превращается ноль (либо меньше 5, в зависимости от настроек).
Количество запросов к базе MySQL в CS-Cart без кеширования доходит до 300 на каждой странице сайта. С включенным кешированием: 120-150 запросов. Это катастрофа! Это бесконечная нагрузка на базу данных. Сайт на CS-Cart всегда будет медленным и требовательным к ресурсам.
MySQL терпит от CS-Cart
Конечно, запросы могут быть быстрыми. К примеру, 300 запросов на выборку 10 строк из одной таблицы будут делаться примерно сотую долю секунды. Но разработчики CS-Cart решили, что это будет слишком скучно. Поэтому они запрограммировали мега запросы! К примеру, запрос вывода блока популярных товаров. Этот запрос объединяет 7 (!) таблиц одновременно (тело запроса смотрите после абзаца). И при наличии 20 000 товаров в магазине этот SQL запрос почти 1 секунду:
SELECT SQL_CALC_FOUND_ROWS products.product_id, IF(shared_descr.product_id IS NOT NULL, shared_descr.product, descr1.product) as product, popularity.total as popularityFROM cscart_products as productsLEFT JOIN cscart_product_descriptions as descr1 ON descr1.product_id = products.product_id AND descr1.lang_code = 'ru'LEFT JOIN cscart_product_prices as prices ON prices.product_id = products.product_id AND prices.lower_limit = 1INNER JOIN cscart_products_categories as products_categories ON products_categories.product_id = products.product_idINNER JOIN cscart_categories ON cscart_categories.category_id = products_categories.category_id AND (cscart_categories.usergroup_ids = '' OR FIND_IN_SET(0, cscart_categories.usergroup_ids) OR FIND_IN_SET(2, cscart_categories.usergroup_ids) OR FIND_IN_SET(1, cscart_categories.usergroup_ids)) AND cscart_categories.status IN ('A', 'H')LEFT JOIN cscart_product_popularity as popularity ON popularity.product_id = products.product_idLEFT JOIN cscart_ult_product_descriptions shared_descr ON shared_descr.product_id = products.product_id AND shared_descr.company_id = 1 AND shared_descr.lang_code = 'ru' WHERE 1 AND cscart_categories.company_id = 1 AND popularity.total >= 1 AND (products.usergroup_ids = '' OR FIND_IN_SET(0, products.usergroup_ids) OR FIND_IN_SET(2, products.usergroup_ids) OR FIND_IN_SET(1, products.usergroup_ids)) AND products.status IN ('A') AND prices.usergroup_id IN (0, 0, 2, 1) GROUP BY products.product_id ORDER BY popularity.total desc, products.product_id ASC LIMIT 0, 10
Если запрос делается 1 секунду, то при нагрузке в 1 запрос в секунду сайт будет непрерывно занят ожидаем результата от базы данных. Если придёт 2 запроса, то будет сделано второе соединение с базой, которое обрабатывается отдельно.
На хостинге каждому клиенту выделяется 10 соединений с базой данных для работы. В ситуации с CS-Cart и 20 000 товарами это означает, что если взять и просто перезагрузить страницу 10 раз за секунду, то будут заняты все соединения с базой данных и последующие будут ждать. Сайт "ляжет".
Сессии пользователей в CS-Cart
По умолчанию в CS-Cart все сессии пользователей хранятся в базе данных. Такой способ хранения используется на очень больших проектах интернет магазинов с миллионами товаров. Делается в конфигурации из нескольких серверов, когда на одном хранятся сессии, а другие находятся под балансировщиком нагрузки. Но скажем прямо, таких магазинов в инетнете - единицы. Для подавляющего большинства (99.999%) интернет магазинов хранение сессий пользователей в БД неоправданно. Оно не только создаёт запросы к базе данных, но и увеличивает её размер.
Для хранения сессий есть стандартный механизм PHP - хранение сессий в файлах. Оно выгоднее, потому что файлы читаются с диска, а не из оперативной памяти. Оперативной памяти всегда было и будет меньше, чем дискового пространства. И в ней уже находится база данных. Следовательно, если не хранить данные сессий в базе данных, которая обрабатывается в ОЗУ, то сайт может положить в ОЗУ что-то полезное! К примеру, данные акселератора php файлов, чтобы они быстрее выполнялись и сайт работал быстрее. Думаю, напишу об этом отдельную статью...
Одним словом, разработчики CS-Cart большие оптимисты, раз вынесли сессии в базу данных. Они думают, что их CMS будет использоваться на большом проекте. Но как мы видим по мега запросу на 20 000 товаров, который длится почти секунду, это CMS просто не приспособлена к большим проектам.
Сообщество CS-Cart
Если зайти на форумы по CS-Cart, то можно увидеть тонны информации по оптимизации PHP, MySQL. Советов по выбору "быстрого" хостинга. Но если начать вникать в суть обсуждений, то становится ясно, что люди просто несут бред.
Как бы ни оптимизировалось PHP и MySQL серверы, то все равно запрос с объединением 7 таблиц к базе из 20 тысяч товаров будет выполняться долго. Если по-прежнему думаете, что виноват PHP, то можете открыть терминал базы и прописать туда вручную весь этот мега запрос. Появится результат и время исполнения.
Мной было потрачено несколько дней на то, чтобы объяснить владельцу сайта это мысль. Он даже не успокоился, когда собственноручно не ввёл мега запрос в консоль MySQL. У него один ответ: "Виноват PHP, нет Redis...". После чего владелец присылал мне ссылки на магазины, которые работают на CS-Cart со словами: "Видите как быстро работают! А у вас медленный хостинг!". На что я отвечал: "Если смотреть по ссылкам в sitemap, то у присланного сайта меньше 1 тысячи товаров. А у вашего сайта больше 20 тысяч товаров. Ваш должен работать в 20 раз медленнее из-за плохого программирования.".
Сообщество CS-Cart настаивает на том, что надо переезжать на производительные серверы. Но суть в том, что система CS-Cart запрограммирована настолько плохо, что никаких ресурсов не хватит для её быстрой работы. Конечно, можно купить супер дорогой сервер и хвастаться быстрой работой CS-Cart, но надо ли оно?
Выводы о CS-Cart
CS-Cart работает плохо при любом количестве товаров. А если количество товаров больше 1 000, то для CS-Cart желательно использовать суперкомпьютер из списка ТОП-500 в качестве сервера. В любом случае генерируется больше 100 запросов к базе на каждую загрузку страницы, что является абсолютным фиаско.
Я не рекомендую использовать CMS CS-Cart на текущем этапе её жизни. Разработчикам необходимо существенно доработать производительность и оптимизацию.
P.S.
Если всё ещё интересно по поводу запроса с объединением 7 таблиц, то просто приведу данные по количеству строк в этих таблицах для магазина в 20 000 товаров:
cscart_products - 20,575
cscart_product_descriptions - 20,575
cscart_product_prices - 20,575
cscart_products_categories - 39,894
cscart_categories - 213
cscart_product_popularity - 20,577
cscart_ult_product_descriptions - 18,762
В пример привёл только 1 запрос, который попался на глаза. А ведь их там больше сотни на каждую загрузку страницы.
Отправил свои притензии разработчикам CS-Cart. Они зашли на сайт клиента, сделали анализ. В ответ я получил... вопиющую неграмотность... Просто нет слов! Читайте сами:
А теперь разберём ответ разработчиков CS-Cart по порядку.
> в среднем затрачивается около секунды на выполнение всех запросов на главной странице
Для сравнения. На нормальной CMS запросы выполняются примерно за 0.01 секунду. А вот полная компиляция страницы составляет примерно 0.2 секунды. А в CS-Cart только запросы делаются 1 секунду!
> 1. Измените значение следующих директив
Нет. Это абсолютно неадекватные значения
Невозможно отдать 100 мегабайт по sort_buffer_size и join_buffer_size. Потому что это буфер на каждое подключение. То есть если у базы количество подключений max_connections равно 100, то надо умножить сумму буферов на эти 100 подключений. То есть получится, что на подключения будет отдано 100 * (100 МБ от sort_buffer_size и 100 МБ от join_buffer_size) = 20 Гигабайт
20 Гб только на буферы в базу данных, в которой всего 150 мегабайт данных в таблицах?
> 2. Увеличьте значение директивы mysql.connect_timeout до максимально возможной величины.
Нет. Что изменится? Сейчас запросы сбрасываются по таймайту соединения. Будет ли пользователь ждать больше 30 секунд, пока сайт отлипнет? Нет
> мы оформили пробный заказ и было выполнено 220 запросов
- это уже катастрофа! 220 запросов на что? Добавить товар в корзину?! Почему в других CMS для этого хватает 20 запросов?
Официально объявляю. CS-Cart - это худшая CMS для создания интернет магазина.
CMS, в которой при создании заказа делается 220 запросов к базе. А скорость работы сайта зависит от количества товаров в нём. Вишенка на торте - восхитительные рекомендации от разработчиков увеличить буферы сортировок в БД до размера в 5 (!) раз большего, чем таблица с товарами.
CS-Cart сделана школьниками на коленке. Эта CMS - страшный сон любого владельца бизнеса. Это мина замедленного действия. С виду кажется, что всё нормально, а под капотом у неё всё сделано на "отвали".
Есть множество сайтов с товарами 30-120 тысяч, работают как обычные сайты. Например сайт в 28000 товаров спокойно стоит на vps 2 ядра 4 гига за 20$. Все зависит от настройки сервера и посещаемости сайта.
Согласен полностью. Влип в CS-Cart и несу этот крест уже почти 10 лет. И огромное количество времени потратил в поисках способа оптимизации БД. Но - нет. При увеличении количества товаров скорость работы сайта падает катастрофически... И, да, я хоть и чайник, но мне казалось диким километровая длинна строки запроса к БД - поэтому одно из действенных способов "оптимизации" это нафиг убирать все украшательства типа каруселей с товарами, как бы не хотелось их иметь - на CS-Cart это непозволительная роскошь.
Отдельная боль - миграция. Даже прыгнуть через несколько версий самого ЦС-Карта это ад, так как нельзя просто взять и выгрузить табличку с товарами. Она там не одна, мне кажется что даже и не пять.