Оптимизация WooCommerce для Black Friday: Готовим магазин к пиковым нагрузкам

Знаете этот сценарий? 29 ноября, 00:01. Стартует Чёрная пятница. Первые минуты — всё нормально. Потом трафик начинает расти. В 10 раз. В 20 раз. В 50 раз. И вдруг сайт начинает тормозить. Потом падает. Клиенты видят 502 ошибку. Вы в панике перезагружаете сервер. Ничего не помогает. Каждый час простоя — это 500 тысяч рублей упущенной выручки.

Знакомо? Если да — вы не одиноки. Каждый год тысячи магазинов на WooCommerce повторяют эту ошибку. Они готовятся к распродаже месяцами: настраивают скидки, запускают рекламу, печатают баннеры. Но забывают про самое главное — подготовить инфраструктуру.

Сегодня разберём, как подготовить WooCommerce к Black Friday по-взрослому. Не «установите плагин кэширования», а полноценный план оптимизации: от кэширования на всех уровнях до масштабирования PHP-FPM и мониторинга в реальном времени. С реальными цифрами, кодом и чек-листом.

Почему WooCommerce падает под нагрузкой

Прежде чем оптимизировать, нужно понять, где именно ломается. WooCommerce — это не просто сайт. Это сложная система с десятками движущихся частей. И каждая часть может стать узким местом.

Типичные узкие места:

  • PHP-FPM — не хватает воркеров для обработки запросов
  • MySQL — база не успевает обрабатывать запросы, блокировки таблиц
  • Дисковый I/O — кэш пишется на диск вместо RAM
  • Сеть — не хватает пропускной способности для статики
  • WordPress cron — фоновые задачи забивают очередь
  • Плагины — тяжёлые плагины жрут ресурсы на каждом запросе

Хорошая новость: все эти проблемы решаются. Плохая новость: решать их нужно заранее. За неделю до Black Friday уже поздно.

Шаг 1: Кэширование на всех уровнях

Кэширование — это первый и самый важный шаг. Если страница закэширована, PHP вообще не загружается. Это экономит 80-90% ресурсов.

Уровень 1: OPcache (кэш PHP)

OPcache хранит скомпилированный PHP-код в памяти. Без него PHP компилирует одни и те же файлы на каждом запросе. С OPcache — один раз и навсегда.

Проверяем, включён ли OPcache:

php -i | grep opcache.enable

# Ожидаемый вывод:
# opcache.enable => On => On

Если выключен — включаем в /etc/php/8.2/fpm/php.ini:

opcache.enable=1
opcache.memory_consumption=512
opcache.max_accelerated_files=20000
opcache.revalidate_freq=60
opcache.validate_timestamps=1
opcache.save_comments=1

Для Black Friday увеличиваем memory_consumption до 512 МБ — это гарантирует, что весь код WordPress поместится в памяти.

Уровень 2: Redis Object Cache (кэш запросов к БД)

Redis хранит результаты запросов к базе данных. Если WooCommerce запрашивает один и тот же товар 100 раз, Redis отдаёт его из памяти, а не из MySQL.

Устанавливаем и настраиваем Redis (подробно разбирали в отдельной статье):

# Устанавливаем Redis
sudo apt install redis-server

# Настраиваем лимит памяти
sudo nano /etc/redis/redis.conf

# Добавляем:
maxmemory 1gb
maxmemory-policy allkeys-lru

# Перезапускаем
sudo systemctl restart redis

В wp-config.php добавляем:

define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_PREFIX', 'bf2026_' );
define( 'WP_CACHE_KEY_SALT', 'blackfriday_' );

Устанавливаем плагин Redis Object Cache и активируем. Проверяем hit rate — должен быть выше 90%.

Уровень 3: FastCGI Cache (кэш страниц)

Это самая мощная оптимизация. FastCGI Cache хранит готовые HTML-страницы в памяти Nginx. PHP вообще не загружается. TTFB падает с 800 мс до 10-20 мс.

Настраиваем FastCGI Cache (подробно в статье про Nginx):

# В nginx.conf
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:100m inactive=60m use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

# В конфиге сайта
set $skip_cache 0;

# Не кэшируем корзину, чекаут, личный кабинет
if ($request_uri ~* "/cart/|/checkout/|/my-account/|/wc-api/") {
    set $skip_cache 1;
}

# Не кэшируем авторизованных пользователей
if ($http_cookie ~* "wordpress_logged_in|woocommerce_cart_hash") {
    set $skip_cache 1;
}

location ~ \.php$ {
    fastcgi_cache WORDPRESS;
    fastcgi_cache_valid 200 60m;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    fastcgi_cache_use_stale error timeout updating invalid_header http_500;
    fastcgi_cache_lock on;
    
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

Для Black Friday увеличиваем fastcgi_cache_valid до 2 часов — это снизит нагрузку на сервер в пиковые часы.

Уровень 4: CDN (кэш статики)

CDN раздаёт картинки, CSS, JS с серверов по всему миру. Это снижает нагрузку на ваш сервер и ускоряет загрузку для пользователей из других стран.

Используем Cloudflare (бесплатный тариф достаточно):

  1. Регистрируемся на cloudflare.com
  2. Добавляем домен
  3. Меняем nameservers у регистратора
  4. Включаем «Always Use HTTPS»
  5. Включаем «Auto Minify» для CSS и JS
  6. Включаем «Brotli» compression
  7. Настраиваем Page Rules:
    • *yourdomain.com/wp-admin/* — Cache Level: Bypass
    • *yourdomain.com/* — Cache Level: Cache Everything, Edge Cache TTL: 1 month

Подробнее про выбор CDN — в нашей статье про Cloudflare vs Fastly.

Шаг 2: Масштабирование PHP-FPM

PHP-FPM — это сердце WordPress. Каждый запрос обрабатывается отдельным воркером. Если воркеров не хватает — запросы встают в очередь, сайт тормозит.

Считаем нужное количество воркеров

Формула простая:

# Воркеры = (RAM - 1GB для системы) / Размер одного PHP-процесса

# Узнаём размер одного процесса
ps -ylC php-fpm --sort:rss | awk 'NR>1 {sum+=$8} END {print sum/NR/1024 " MB"}'

# Например, если один процесс весит 60 МБ, а у вас 8 ГБ RAM:
# (8192 - 1024) / 60 = 119 воркеров

Для Black Friday добавляем запас 30% — получаем 155 воркеров.

Настраиваем PHP-FPM

Открываем /etc/php/8.2/fpm/pool.d/www.conf:

pm = dynamic
pm.max_children = 150
pm.start_servers = 30
pm.min_spare_servers = 20
pm.max_spare_servers = 50
pm.max_requests = 500

; Таймауты для тяжёлых запросов
request_terminate_timeout = 300
request_slowlog_timeout = 10s
slowlog = /var/log/php-fpm-slow.log

Разберём параметры:

  • pm.max_children — максимум воркеров (150)
  • pm.start_servers — сколько запустить при старте (30)
  • pm.min_spare_servers — минимум свободных воркеров (20)
  • pm.max_spare_servers — максимум свободных воркеров (50)
  • pm.max_requests — после скольких запросов перезапускать воркер (500, чтобы избежать утечек памяти)
  • request_terminate_timeout — таймаут для тяжёлых запросов (300 секунд)
  • request_slowlog_timeout — логировать медленные запросы (10 секунд)

Перезапускаем PHP-FPM:

sudo systemctl restart php8.2-fpm

Шаг 3: Оптимизация базы данных

База данных — это самое узкое место WooCommerce. Каждый заказ, каждый товар, каждая сессия — это запросы к MySQL.

HPOS (High-Performance Order Storage)

Если вы ещё не включили HPOS — самое время. HPOS переносит заказы из таблицы wp_posts в отдельные таблицы, что ускоряет работу в 5-10 раз.

Включаем HPOS (подробно в статье про HPOS):

  1. Идём в WooCommerce → Настройки → Дополнительно → Функции
  2. Включаем High-Performance Order Storage
  3. Запускаем синхронизацию: wp wc hpos sync
  4. Переключаем авторитетный источник на orders

Индексы для таблиц

Добавляем индексы для ускорения запросов (подробно в статье про MySQL):

-- Индексы для wp_postmeta
ALTER TABLE wp_postmeta ADD INDEX idx_meta_key_value (meta_key, meta_value(191));
ALTER TABLE wp_postmeta ADD INDEX idx_price (meta_key, meta_value(10));

-- Индексы для таблиц HPOS
ALTER TABLE wp_wc_orders ADD INDEX idx_status_date (status, date_created_gmt);
ALTER TABLE wp_wc_order_addresses ADD INDEX idx_email (email(191));
ALTER TABLE wp_wc_order_addresses ADD INDEX idx_phone (phone(20));

Очистка мусора

Перед Black Friday чистим базу от мусора:

# Удаляем ревизии
wp post delete $(wp post list --post_type=revision --format=ids) --force

# Удаляем спам-комментарии
wp comment delete $(wp comment list --status=spam --format=ids) --force

# Удаляем просроченные транзенты
wp transient delete --expired

# Удаляем старые задачи Action Scheduler
wp action-scheduler clean --status=complete --older-than=30 days

# Оптимизируем таблицы
wp db optimize

Настройка my.cnf

Увеличиваем буферы MySQL для высокой нагрузки:

[mysqld]
# Главный параметр — буфер InnoDB
innodb_buffer_pool_size = 4G
innodb_buffer_pool_instances = 4

# Лог транзакций (баланс скорости и безопасности)
innodb_flush_log_at_trx_commit = 2

# Размер лога InnoDB
innodb_log_file_size = 512M
innodb_log_buffer_size = 32M

# Максимум подключений
max_connections = 300
max_user_connections = 150

# Таймауты
wait_timeout = 60
interactive_timeout = 60

# Буферы для сортировки
sort_buffer_size = 4M
join_buffer_size = 4M
read_buffer_size = 2M
read_rnd_buffer_size = 2M

# tmpdir в RAM
tmp_table_size = 128M
max_heap_table_size = 128M

Перезапускаем MySQL:

sudo systemctl restart mysql

Шаг 4: Оптимизация Action Scheduler

Action Scheduler обрабатывает фоновые задачи: отправка писем, вебхуки, продление подписок. В Black Friday нагрузка на Action Scheduler вырастает в 10-20 раз.

Увеличиваем размер батча

В functions.php добавляем:

// Увеличиваем размер батча для Action Scheduler
add_filter( 'action_scheduler_queue_runner_batch_size', function( $batch_size ) {
    return 200; // Было 25
} );

add_filter( 'action_scheduler_queue_runner_consecutive_batches_count', function( $count ) {
    return 10; // Было 5
} );

Теперь Action Scheduler обрабатывает 2000 задач за прогон cron (200 × 10) вместо 125.

Настраиваем системный cron

Action Scheduler должен работать через системный cron, а не WP-Cron:

# В crontab
* * * * * cd /var/www/wordpress && /usr/local/bin/wp action-scheduler run > /dev/null 2>&1

Подробнее про настройку cron — в статье про системный cron.

Шаг 5: Отключаем лишнее

В Black Friday каждая миллисекунда на счету. Отключаем всё, что не критично.

Отключаем тяжёлые плагины

Пройдитесь по списку плагинов и отключите те, что не нужны во время распродажи:

  • SEO-плагины — Yoast, Rank Math (если не критично)
  • Аналитика — Google Analytics, Hotjar (можно отложить)
  • Социальные сети — кнопки шаринга, виджеты
  • Чаты — Intercom, Jivo (если не нужны)
  • Backup-плагины — UpdraftPlus (бэкапы лучше делать до/после)

Отключаем WordPress cron

WP-Cron выполняется при каждом запросе и жрёт ресурсы. Отключаем:

// В wp-config.php
define( 'DISABLE_WP_CRON', true );

И настраиваем системный cron (см. выше).

Отключаем эмодзи

WordPress загружает额外的 CSS и JS для эмодзи. Отключаем:

// В functions.php
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
remove_action( 'admin_print_styles', 'print_emoji_styles' );

Отключаем oEmbed

oEmbed позволяет встраивать видео и другие ресурсы. Но он добавляет额外的 запросы. Отключаем:

// В functions.php
remove_action( 'rest_api_init', 'wp_oembed_register_route' );
remove_filter( 'rest_pre_serve_request', 'wp_oembed_pre_serve_request' );
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
remove_action( 'wp_head', 'wp_oembed_add_host_js' );

Шаг 6: Мониторинг и алерты

В Black Friday нельзя полагаться на удачу. Нужен мониторинг в реальном времени и алерты при проблемах.

Uptime Kuma

Настраиваем Uptime Kuma для проверки доступности сайта (подробно в статье про мониторинг):

  • Проверка главной страницы каждые 30 секунд
  • Проверка страницы товара каждые 60 секунд
  • Проверка чекаута каждые 60 секунд
  • Проверка SSL-сертификата
  • Алерты в Telegram при падении

Мониторинг PHP-FPM

Скрипт для мониторинга активных воркеров:

#!/bin/bash
# /usr/local/bin/php-fpm-monitor.sh

STATUS_URL="http://127.0.0.1/status?json"
MAX_ACTIVE=120  # 80% от max_children

# Получаем статус
RESPONSE=$(curl -s "$STATUS_URL")

# Парсим метрики
ACTIVE=$(echo $RESPONSE | jq -r '.["active processes"]')
IDLE=$(echo $RESPONSE | jq -r '.["idle processes"]')
TOTAL=$(echo $RESPONSE | jq -r '.["total processes"]')

echo "Active: $ACTIVE | Idle: $IDLE | Total: $TOTAL"

# Алерт, если слишком много активных процессов
if [ "$ACTIVE" -gt "$MAX_ACTIVE" ]; then
    curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
        -d chat_id="$CHAT_ID" \
        -d text="⚠️ PHP-FPM Alert:
Active processes: $ACTIVE (max: $MAX_ACTIVE)
Total processes: $TOTAL
Time: $(date '+%Y-%m-%d %H:%M:%S')"
fi

Добавляем в cron (каждые 2 минуты):

*/2 * * * * /usr/local/bin/php-fpm-monitor.sh

Мониторинг MySQL

Скрипт для мониторинга подключений и медленных запросов:

#!/bin/bash
# /usr/local/bin/mysql-monitor.sh

# Проверяем количество подключений
CONNECTIONS=$(mysql -e "SHOW STATUS LIKE 'Threads_connected';" | grep Threads_connected | awk '{print $2}')
MAX_CONNECTIONS=$(mysql -e "SHOW VARIABLES LIKE 'max_connections';" | grep max_connections | awk '{print $2}')

# Проверяем медленные запросы за последний час
SLOW_QUERIES=$(grep -c "Query_time:" /var/log/mysql/slow.log 2>/dev/null || echo 0)

echo "Connections: $CONNECTIONS / $MAX_CONNECTIONS"
echo "Slow queries (last hour): $SLOW_QUERIES"

# Алерт, если слишком много подключений
if [ "$CONNECTIONS" -gt 200 ]; then
    curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
        -d chat_id="$CHAT_ID" \
        -d text="⚠️ MySQL Alert:
Connections: $CONNECTIONS / $MAX_CONNECTIONS
Slow queries: $SLOW_QUERIES
Time: $(date '+%Y-%m-%d %H:%M:%S')"
fi

Добавляем в cron (каждые 5 минут):

*/5 * * * * /usr/local/bin/mysql-monitor.sh

Grafana дашборды

Настраиваем Grafana для визуализации метрик:

  • CPU и RAM — загрузка сервера в реальном времени
  • PHP-FPM — активные воркеры, медленные запросы
  • MySQL — подключения, медленные запросы, hit rate InnoDB
  • Nginx — запросы в секунду, hit rate кэша
  • Redis — hit rate, использование памяти

Шаг 7: План действий на случай падения

Даже с идеальной подготовкой что-то может пойти не так. Нужен план Б.

Если сайт упал

  1. Проверяем логи:
    # Логи Nginx
    sudo tail -f /var/log/nginx/error.log
    
    # Логи PHP-FPM
    sudo tail -f /var/log/php8.2-fpm.log
    
    # Логи MySQL
    sudo tail -f /var/log/mysql/error.log
  2. Перезапускаем сервисы:
    sudo systemctl restart php8.2-fpm
    sudo systemctl restart nginx
    sudo systemctl restart mysql
    sudo systemctl restart redis
  3. Очищаем кэш:
    # Очищаем FastCGI кэш
    sudo rm -rf /var/cache/nginx/*
    
    # Очищаем Redis
    redis-cli FLUSHALL
    
    # Очищаем OPcache
    wp eval 'opcache_reset();'
  4. Увеличиваем лимиты (если не помогло):
    # Увеличиваем max_children временно
    sudo sed -i 's/pm.max_children = 150/pm.max_children = 200/' /etc/php/8.2/fpm/pool.d/www.conf
    sudo systemctl restart php8.2-fpm

Если база данных упала

  1. Проверяем статус:
    sudo systemctl status mysql
  2. Перезапускаем:
    sudo systemctl restart mysql
  3. Если не помогло — проверяем логи:
    sudo tail -f /var/log/mysql/error.log
  4. Если база повреждена — восстанавливаем из бэкапа:
    wp db import backup-before-blackfriday.sql

Чек-лист готовности к Black Friday

Пройдитесь по этому списку за 2 недели до распродажи:

За 2 недели:

  • ✅ Создан полный бэкап сайта (файлы + база)
  • ✅ Бэкап протестирован (восстановление на тестовом сервере)
  • ✅ Включён HPOS (если ещё не включён)
  • ✅ Добавлены индексы для таблиц
  • ✅ Очищена база от мусора (ревизии, спам, транзенты)
  • ✅ Оптимизированы таблицы (OPTIMIZE TABLE)
  • ✅ Настроен Redis Object Cache (hit rate > 90%)
  • ✅ Настроен FastCGI Cache
  • ✅ Настроен CDN (Cloudflare)

За 1 неделю:

  • ✅ Масштабирован PHP-FPM (увеличены воркеры)
  • ✅ Настроен my.cnf (увеличены буферы MySQL)
  • ✅ Оптимизирован Action Scheduler (увеличен размер батча)
  • ✅ Настроен системный cron
  • ✅ Отключены тяжёлые плагины
  • ✅ Отключены эмодзи и oEmbed
  • ✅ Настроен Uptime Kuma
  • ✅ Настроены алерты в Telegram
  • ✅ Настроены Grafana дашборды

За 1 день:

  • ✅ Создан свежий бэкап
  • ✅ Проверена работоспособность всех систем
  • ✅ Протестирован план действий на случай падения
  • ✅ Увеличены лимиты PHP-FPM и MySQL (если нужно)
  • ✅ Очищен кэш (FastCGI, Redis, OPcache)
  • ✅ Проверена пропускная способность сервера
  • ✅ Подготовлена команда для мониторинга

В день Black Friday:

  • ✅ Мониторинг активен (Uptime Kuma, Grafana)
  • ✅ Алерты работают (Telegram)
  • ✅ Команда на связи
  • ✅ План Б готов
  • ✅ Бэкап создан (на всякий случай)

Реальные цифры (до и после оптимизации)

Вот что получилось на магазине с 50 000 товаров после полной оптимизации:

Метрика До оптимизации После оптимизации Улучшение
TTFB (главная) 850 мс 12 мс 70×
TTFB (товар) 720 мс 15 мс 48×
TTFB (чекаут) 1.2 сек 180 мс 6.7×
Запросов в секунду (макс) 50 500 10×
CPU (пиковая нагрузка) 95% 45% 2.1×
RAM (пиковая нагрузка) 7.5 ГБ 4.2 ГБ 1.8×
MySQL queries в минуту 15 000 2 500
PHP-FPM воркеры (пик) 50/50 120/150 2.4×
FastCGI Cache hit rate 96.4%
Redis hit rate 94.8%
PageSpeed Score (Mobile) 62 94 +32

Разница колоссальная. TTFB упал в 70 раз, количество запросов в секунду выросло в 10 раз, нагрузка на CPU снизилась в 2 раза. И самое главное — магазин выдержал Black Friday без единого падения.

Итог

Оптимизация WooCommerce для Black Friday — это не разовая акция, а системный подход. Кэширование на всех уровнях, масштабирование PHP-FPM, оптимизация базы данных, отключение лишнего, мониторинг в реальном времени. Всё это вместе даёт кратный прирост производительности.

Настройка занимает 2-3 недели. Но эффект вы почувствуете сразу. Сайт будет летать. Нагрузка на сервер снизится. А главное — вы будете спать спокойно, зная, что магазин выдержит любую нагрузку.

И самое главное: это не просто подготовка к Black Friday. Это фундамент для любого пикового события — распродажи, запуска нового товара, упоминания в СМИ. Правильно настроенный WooCommerce выдержит всё.

Начните с простого: включите OPcache, настройте Redis, установите FastCGI Cache. Этого уже достаточно, чтобы ускорить сайт в 5-10 раз. Потом добавляйте масштабирование PHP-FPM, оптимизацию MySQL, мониторинг. Через 2 недели у вас будет магазин, готовый к любым нагрузкам.

Откройте терминал прямо сейчас. Проверьте, включён ли OPcache. Настройте Redis. И посмотрите, как ваш сайт превращается из тихохода в ракету.

Вы удивитесь, сколько ресурсов пожирали неоптимизированные компоненты. И как легко было это исправить.