Генерация кэша CS-Cart и возможный race condition

Здравствуйте.

Размещая пользователей с интернет-магазинами на Cs-cart на хостинге, не однократно сталкивались с таким моментом. Например, владелец сайта очищает кеш из админ-панели CMS или же переключает его со стандартного file, database на redis, в результате чего, первое открытие всегда на порядок дольше (это понятно нам, хоть и не понятно владельцеам магазинов). И до тех пор пока кеш не сгенерируется в полном объёме, веб-сайт не будет открываться, а будет “висеть” при каждом заходе пользователя или любого другого HTTP запроса на домен веб-сайта.

Суть вопроса. В момент первой генерации кеша, не важно, будь то установка модуля администратором сайта с авто-очисткой кеша или переключение кеша, происходит следующее:

Первый посетитель своим HTTP запросом провоцируют генерацию кеша. В этот момент могут одновременно зайти ещё 10-20 человек или более (на крупных магазинах это в порядке вещей).
В результате, мы получаем в такой ситуаци с сайтом достаточно большую нагрузку на сервер, свыше ~1200% 1 CPU - 12 ядер. При этом используются 12 ядерные процессоры Xeon по 2шт в платформе, в сумме получаем 24 ядер/потоков на сервере. Один веб-сайт, с лёгкостью утилизирует свыше 12 ядер под 100% каждое ядро процессор при создании кеша по причине того, что для каждого посетителя запускается параллельная/повторная генерация кеша, когда предыдущая ещё не завершена, в итоге процесс создания кеша от обычных 15-30 секунд растягивается до минуты, а то и более если нагружен сервер в этот момент. Нагрузка на CPU при этом всё так же растёт от каждого дочернего apache процесса, которые длительное время не могут выполниться и завершиться (идёт создание кеша).

Из чего можно сделать вывод, что это не совсем нормальное поведение и это что-то схожее с так называемым “Race Condition”, когда каждый новый заход посетителя на сайт (обновление страницы) или заход поисковых ботов (по другому новый поток), провоцирует всё новую и новую попытку пересоздать кеш, тем самым попросту приводя к колоссальной нагрузке на CPU и как результат, повышенную нагрузку на сервере. Начинает расти Load Average до 25 и выше со всеми вытекающими для остальных веб-сайтов в случае если таковые имеются на том же сервере.

Эта проблема замечалась нами на протяжении нескольких лет при анализе причин кратковременной повышенной нагрузки CS-cart, но мы до конца не могли понять что именно является причиной такого скачка нагрузки на CPU. Есть мысли попытаться как-то совместно этот вопрос решить. Зачем? Обычные владельцы интернет-магазинов сразу же считают, что текущий сервер им не подходит и плохой (их понять можно) и они могут выкидывать запредельные суммы средств всё на новый и новый более мощный сервер, который если и поможет, то только отчасти, во-вторых, бывает сложно объяснять технические сложные моменты таким пользователям из-за чего это происходит и как с этим следует бороться.

Так как на первый взгляд это может показаться не совсем багом, а скорее особенностью, чтобы облегчить возможный дальнейший ход поиска решения проблемы, можно попытаться придумать нечто следующее. Возможно в том участке кода CS-Cart, который отвечает за генерацию кеша, попробовать добавить какое-либо условие, которое не давало бы возможности параллельно инициировать запуск генерации кеша.
Простой пример:
При попытке открыть веб-сайт без созданного кеша (в момент возможного горячего посещения его), в корне веб-сайта создавать некий файл .cache-delay, когда запускается участок кода, ответственный за генерацию кеша, в головном роуте/логике ядра CS-Cart устанавливается условие, что до тех пор, пока существует файл .cache-delay, на любые последующие HTTP запросы к сайту, он возвращает, например, ошибку - заглушку “503 - Магазин на обслуживании, зайдите позже…” (некая временная асинхронность). А как только завершается сценарий создания кеша, в коде срабатывает условие, которое проверяет наличие файла .cache-delay и удаляет его. В итоге получаем в теории отсутствие некого Race Condition, отсутствие длительного создания кеша и проблем с большой нагрузкой от этого действия на посещаемом сайте.

Ниже будет пример на видео, снаятое на тапочек. Показатели нагрузки в мониторинге и top в момент когда происходит подобная проблема. Да, возможно генерация посещений с помощью host-tracker не совсем корректна, но это не меняет сути. Можно тоже самое воспроизвести, просто открывая по соседству 5-10 вкладок с сайтом в момент первого создания кеша.
yadi.sk/i/npfxxBfu3ViSbk

железо

Конфиг железа:
2 x Xeon 2.4Ghz
32GB RAM
SSD 1TB RAID1

8 лайков

подверждаю, хостер тоже писал про аналогичную ситуацию, иногда создаются пиковые нагрузки до 75-100% ни чем объективным не обусловленные, по логам видно, что при индексации страниц роботами, что видимо и приводит к выше описанной ситуации

Не знаю технической стороны вопроса.
Может быть можно создать какой-то модуль, который, как :robot: по расписанию, например ночью, выполнял запросы на генерацию кеша? Тем самым не пользователь и не робот ПС ожидают генерации, тем самым ухудшение отношения и со стороны робота (у него время на индексацию ограниченно) и пользователя.
Такое вообще возможно?

1 лайк

Добрый день, проблема такая действительно есть. В ближайшее время изучим и попробуем найти оптимальные варианты решения.
Спасибо за обратную связь.

2 лайка

Вчера под вечер ровно то же в голову пришло.
Очевидно необходим автопроходчик.

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

1 лайк

Это всё костыльные решения (проходы по сайтмапу и т.д.) и изначально нужно организовать правильный подход к первой генерации кеша хотя бы для главной страницы. Самой простой пример для избежания race condition описан в первом сообщении. В теории этого вполне достаточно для решения проблемы с нагрузкой при отсутствии кеша и наплыва посетителей, ботов.

Прогрев кеша пока был и остается единственным вменяемым решением в большинстве проектов. Но каждый судит из своей колокольни и исходя из своего опыта.

1 лайк

Давно хотел спросить - как быть с кэшем, если используется модуль геолокации с блоком, выводящим название населенного пункта посетителя?
Получается, подогрев кэша нужно делать для всех более-менее значимых городов?

Кешируются блоки и выборки из базы данных, app/schemas/block_manager/blocks.php тут можно посмотреть что кешируется. Аддоны расширяют эту схему.

Тут надо делать с оглядкой, например, если в момент, когда существует файл .cache-delay перегрузить сервак, файл останется, и будет висеть вечно пока не удалить его руками. Такое непотребство сейчас существует с модулем “YML экспорт”. Так что нужно проверять время создания и если оно слишком старое, удалять его и запускать процесс вновь.

Добрый день, для решения проблем с race condition в версии 4.9.1 появится механизм блокировок.
Из коробки блокировки будут внедрены в:

  • Рендер блоков, при условии, что блок кешируется
  • Компиляция стилей
  • Объединение js скриптов

Для новых установок блокировки будут включены по умолчанию, для обновляющихся блокировки будут выключены.
Для включения блокировок необходимо внести изменения в конфигурационный файл (config.local.php):

$config['lock_backend'] = 'database';
4 лайка

Скажите, что вписывать database или redis?
если тут так
$config[‘session_backend’] = ‘redis’;
просто не очень понимаю связано оно или нет.

вписали database, как указано и полно ошибок такого вида в журнале и похоже они возникают как раз когда чистится кеш.

Ошибки

Stack trace:
#0 [internal function]: Tygh\Backend\Session\Redis->query(‘hmSet’, ‘session:SG:09b5…’, Array)
#1 /var/www/g01/data/www/САЙТ/app/Tygh/Backend/Session/Redis.php(244): call_user_func_array(Array, Array)
#2 [internal function]: Tygh\Backend\Session\Redis->query(‘hmSet’, ‘session:SG:09b5…’, Array)
#3 /var/www/g01/data/www/САЙТ/app/Tygh/Backend/Session/Redis.php(244): call_user_func_array(Array, Array)
#4 [internal function]: Tygh\Backend\Session\Redis->query(‘hmSet’, ‘session:SG:09b5…’, Array)
#5 /var/www/g01/data/www/САЙТ/app/Tygh/Backend/Session/Redis.php(244): call_user_func_array(Array, Array)
#6 [internal function]: Tygh\Backend\Session\Redis->query(‘hmSet’, ‘session:SG:09b5…’, Array)
#7 /var/www/g01/data/www/САЙТ/app/Tygh/Backend/Session/Redis.php(244): call_user" while reading upstream, client: 46.148.182.234, server: САЙТ, request: “GET /favicon.ico HTTP/2.0”, upstream: “fastcgi://unix:/var/www/php-fpm/g01.sock:”, host: “САЙТ”, referrer: “https://САЙТ/santehnika/mebel-dlya-vannyh-komnat-i-zerkala/?gclid=CjwKCAiA1ZDiBRAXEiwAIWyNC0rnlD8SpEDnqT3Cz74-TAEOYkm1Km-NlURqHO_qDO0EAisH
2019/01/21 00:43:18 [error] 737#737: *214844 FastCGI sent in stderr: "PHP message: PHP Fatal error: Uncaught Tygh\Exceptions\DatabaseException: Sessions: can not connect to the Redis server in /var/www/g01/data/www/САЙТ/app/Tygh/Backend/Session/Redis.php:247

Нужно просто добавить в конфиг новую строку $config[‘lock_backend’] = ‘database’;
Значение у $config[‘session_backend’] оставляйте как есть.

как есть это с Redis?

Ну да, это же разный настройки. Одна для сессий, другая для блокировок.

вот к сожалению когда так включено, то засыпает ошибками и иногда страницы вообще грузят просто ошибку Редиса с табличкой Service unavaible, дошло до того, что они уже и в индекс Гугла попали…
сейчас отключил и ошибок пока нет
$config[‘lock_backend’] = ‘dummy’;

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

1 лайк

Проще чистить кеш в моменты минимальной нагрузки, а потом любым спайдером (да тем же content-downloader) пробежаться по сайту и перегенерить кэш…

Что бы использовать редис - нужно его установить, настроить. Для этого нужна либо впска либо выделенные сервер с достаточным количеством оперативки.