MAATRIX / Блог / Рассылка на 200 000 адресов: что будет с сайтом через 90 секунд

Рассылка на 200 000 адресов: что будет с сайтом через 90 секунд

MAATRIX

Кнопка «Отправить» в сервисе рассылок нажата, письма ушли на 200 000 адресов — для маркетинга задача выполнена, а для сервера она только начинается. Первые полторы минуты после массовой отправки — это не плавный рост трафика, к которому сервер привык в обычные дни, а резкий синхронный всплеск: тысячи людей открывают почти одинаковое письмо в одну и ту же минуту и переходят по одной и той же ссылке. Разберём, что происходит в эти 90 секунд, чем это отличается от обычного трафика и какие меры реально держат посадочную страницу на ногах.

Что происходит в первые 90 секунд после отправки

Даже хороший ESP редко отправляет всю базу одномоментно — он ставит письма в очередь к SMTP-серверам получателей и распределяет отправку по пулу IP, чтобы не спровоцировать спам-фильтры. Но с точки зрения получателя это почти неважно: почтовый ящик обрабатывает входящий поток от знакомого отправителя пачками, и разброс по факту составляет секунды, а не часы.

Дальше идут два параллельных процесса, которые сервер видит как одну и ту же нагрузку на один и тот же URL.

Первый — автоматическое сканирование ссылок. Крупные почтовые провайдеры проверяют ссылки в письме ещё до того, как человек его открыл: Microsoft 365 с Safe Links сканирует URL сразу при доставке, антивирусные прокси корпоративных шлюзов делают то же самое, Gmail проксирует картинки из письма через свои серверы. В первые секунды после доставки на посадочную страницу приходит волна запросов с IP дата-центров почтовых провайдеров, а не от читателей — но она полноценно грузит TCP-соединения, TLS-хендшейк и рендеринг страницы.

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

Сложите оба процесса — и получится не плавный рост, а скачок нагрузки на конкретный URL в конкретную минуту, происходящий синхронно у тысяч независимых людей и ботов.

Почему это не похоже на обычный органический трафик

Разница не только в скорости роста, но и в структуре запросов — и именно это ломает интуицию тех, кто привык мерить нагрузку в терминах «сайт держит X запросов в секунду в среднем».

Органический трафик — из поиска, соцсетей, прямых заходов — размазан по множеству разных страниц, кеш каждой прогревается постепенно, а даже дневной пик нарастает за десятки минут, оставляя время автоскейлингу среагировать. Трафик из рассылки устроен ровно наоборот:

  • Один URL. Все 200 000 писем ведут на одну и ту же посадочную страницу (в лучшем случае — на несколько вариантов A/B-теста). Весь удар приходится не на инфраструктуру в среднем, а на один код пути: один маршрут, один запрос к базе, один кеш-ключ.
  • Одна секунда. Всплеск концентрируется в узком окне, а не растягивается на часы. Автоскейлинг реагирует на возросшую нагрузку с задержкой в минуты — новый инстанс поднимется тогда, когда пик уже прошёл.
  • Холодный кеш в момент максимальной нагрузки. Если страницу не открывали последние сутки, TTL истёк, и первый запрос после рассылки — это не одиночный визит, а сразу тысяча параллельных запросов, синхронно промахивающихся мимо кеша в origin. Это классический thundering herd, только спровоцированный не рестартом кеша, а маркетинговой кампанией с заранее известным временем старта — механика та же, что в статье про эффект стада при прогреве кеша.
  • Похожие паттерны у получателей. Если рассылка ушла преимущественно на несколько крупных почтовых доменов, у каждого свой ритм проверки писем и своя аудитория с похожими привычками — совпадение по времени внутри одного провайдера усиливает пик, а не сглаживает его.

Практический вывод: тестировать сайт нагрузочным тестом «столько-то RPS в среднем за час» для рассылки бессмысленно. Нужен тест именно на короткий пиковый всплеск запросов к одному URL, а не на растянутую по часу равномерную нагрузку.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

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

Сканирование ссылок часто забывают учесть при подготовке к рассылке, хотя оно бьёт по серверу раньше живых пользователей. Если в письме есть трекинговая ссылка (а в массовых рассылках она есть почти всегда — сервис подменяет прямую ссылку на редирект через свой домен для подсчёта кликов), сканер проходит по цепочке редиректов до конечной страницы, полностью её загружая. С точки зрения сервера это неотличимо от обычного визита, кроме одного: User-Agent и диапазон IP часто выдают дата-центр вместо домашнего интернета.

Что это значит практически:

  • Часть нагрузки в первые секунды после отправки — это не будущие клиенты, а автоматические проверки. Игнорировать её нельзя: она реальна для сервера, даже если не даёт конверсий.
  • Одно письмо может быть просканировано несколько раз — разными сервисами защиты (антиспам, антивирус, DLP) на одном и том же корпоративном домене. При базе с заметной долей корпоративных адресов это ощутимо увеличивает первую волну сверх числа реальных подписчиков.
  • Сканеры обычно не выполняют JavaScript и не заходят дальше первой страницы, поэтому не нагружают формы и API — весь удар приходится на статическую отдачу лендинга. Хорошая новость: то же кеширование, которое спасает от реальных пользователей, полностью гасит и эту волну.

Точной доли такого трафика заранее не предсказать — она зависит от состава базы. Ориентируйтесь на логи прошлых рассылок: запросы с IP крупных облачных провайдеров и характерными User-Agent антивирусных прокси в первые секунды после отправки — это она.

Кеш посадочной страницы: что и как кешировать

Первая и самая эффективная линия обороны — не пускать всплеск дальше веб-сервера. Если посадочная страница отдаётся из кеша nginx, для origin-приложения и базы 200 000 открытий выглядят как несколько запросов в минуту — ровно столько, сколько нужно, чтобы обновлять кеш.

Базовая схема nginx как обратного прокси перед приложением:

proxy_cache_path /var/cache/nginx/landing levels=1:2 keys_zone=landing_cache:20m max_size=1g inactive=60m use_temp_path=off;

server {
    listen 443 ssl;
    server_name promo.example.com;

    location /campaign/ {
        proxy_pass http://app_backend;
        proxy_cache landing_cache;
        proxy_cache_key "$scheme$request_method$host$request_uri";
        proxy_cache_valid 200 10m;
        proxy_cache_valid 404 1m;

        # ключевая настройка против стада запросов на промахе кеша
        proxy_cache_lock on;
        proxy_cache_lock_timeout 5s;

        # отдавать устаревшую версию, пока обновляем в фоне
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
        proxy_cache_background_update on;

        add_header X-Cache-Status $upstream_cache_status;
    }
}

Три директивы здесь решают именно проблему синхронного всплеска:

  • proxy_cache_lock — при промахе кеша к origin уходит только один запрос, остальные параллельные запросы к тому же URL ждут его ответа и получают тот же результат из кеша. Без неё тысяча одновременных запросов к холодному кешу превращается в тысячу одновременных запросов к базе — тот самый эффект стада.
  • proxy_cache_use_stale updating — пока идёт обновление кеша, посетители получают чуть устаревшую, но валидную страницу вместо ожидания или ошибки.
  • proxy_cache_valid — держите TTL достаточно длинным для страницы, которая не меняется в реальном времени. Слишком короткий TTL — частая причина, почему «кеш вроде настроен, а сервер всё равно упал».

Важный нюанс: кешировать целиком можно только то, что одинаково для всех посетителей. Если на странице есть персонализация — имя из письма, реферальный код, счётчик остатка мест — вынесите её в отдельный лёгкий запрос с собственным, более коротким кешем, а не отключайте кеш всей страницы целиком.

Отдельный лендинг вместо страницы на боевом сайте

Вторая мера — архитектурная, и она важнее, чем кажется: страница, на которую ведёт массовая рассылка, не должна жить в том же приложении и на той же базе, что личный кабинет, оформление заказа или админка.

Причина простая: даже идеально настроенный кеш не спасает на сто процентов — будут запросы мимо кеша (первый визит на новый вариант A/B-теста, сброс кеша при деплое во время рассылки, поисковые боты, подхватившие свежий URL). Если посадочная страница крутится в общем пуле процессов с основным сайтом, всплеск на ней съедает воркеры и соединения к базе, которые в этот момент нужны действующим клиентам. Получается парадокс: маркетинговая кампания, призванная привлечь новых клиентов, на 90 секунд кладёт покупку у уже привлечённых.

Практическая изоляция выглядит так:

  • Посадочная страница рассылки — отдельный статический билд или лёгкое приложение, часто на поддомене (promo.example.com вместо example.com/promo), с собственным пулом соединений и, если возможно, отдельным сервером или контейнером.
  • Кнопка на этой странице ведёт на основной сайт уже вторым переходом — первый удар трафика принимает лёгкая статическая страница, а до тяжёлой логики (авторизация, каталог с запросами к базе, оформление заказа) доходит уже отфильтрованная и распределённая во времени часть аудитории.
  • Если посадочная страница технически всё равно часть основного сайта, убедитесь хотя бы, что у неё отдельный upstream или лимит соединений в nginx, чтобы всплеск на ней не забирал ресурсы у остального сайта.

Отдельный лендинг проще всего поднять на собственном VPS, не завязанном на инфраструктуру основного продакшена — тогда даже отказ этой страницы под нагрузкой не затронет ничего критичного. Пошаговая настройка такого изолированного лендинга разобрана в статье «Лендинг на своём сервере на VPS с нуля».

Прогрев CDN перед отправкой, а не после

Если посадочная страница отдаётся через CDN — а для рассылки на 200 000 адресов это стоит делать почти всегда, чтобы разнести нагрузку географически, — остаётся последняя ловушка: каждый эдж CDN кеширует независимо и холоден до первого запроса из своего региона. Если первых посетителей из-за синхронного открытия рассылки сразу тысяча, получится тот же thundering herd, что и на уровне nginx, только размноженный на все эджи сразу.

Решение — прогреть кеш заранее, до отправки писем:

  1. За 10-15 минут до отправки вручную сделайте запрос к посадочной странице через каждый значимый эдж CDN (большинство провайдеров позволяют адресовать конкретный PoP или предоставляют API для принудительного прогрева кеша).
  2. Проверьте заголовок ответа, показывающий статус кеша CDN (CF-Cache-Status, X-Cache или аналог) — на прогревающем запросе должно быть MISS, на повторном — HIT. Если повторный запрос всё ещё промахивается, TTL кеша слишком короткий либо в URL есть уникальный параметр (например, тот же трекинговый код), из-за которого CDN считает каждый визит новым — частая причина, разобранная в статье «CDN поставили, а быстрее не стало».
  3. Пример прогрева нескольких эджей вручную (замените адреса на реальные эндпоинты вашего CDN):
#!/usr/bin/env bash
URL="https://promo.example.com/campaign/offer/"
EDGES=("edge-eu.example-cdn.net" "edge-us.example-cdn.net" "edge-asia.example-cdn.net")

for edge in "${EDGES[@]}"; do
  echo "Прогрев $edge:"
  curl -s -o /dev/null -w "  status=%{http_code} time=%{time_total}s\n" \
    --resolve "promo.example.com:443:$(dig +short $edge | head -1)" \
    "$URL"
done
  1. Держите TTL кеша на CDN заведомо длиннее окна активных открытий письма, чтобы кеш не остыл в середине этого окна.
  2. Если рассылка идёт волнами (по часовым поясам или сегментам аудитории), прогревайте кеш перед каждой волной отдельно — TTL мог истечь между волнами, и следующая волна получит холодный старт точно так же, как первая.

Дополнительно стоит закрыть ещё пару пунктов: смоделировать в нагрузочном тесте именно резкий всплеск за 30-60 секунд, а не растянутую нагрузку; поставить отдельный limit_req в nginx на форму или счётчик мест, если они есть на странице, — сама страница спасётся кешем, а запись в базу кешем не закроешь; и предупредить хостинг заранее, если ожидаете экстремальный всплеск, — иначе легитимный синхронный трафик рискует попасть под защиту от DDoS.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Нужно ли постоянно держать посадочную страницу на мощном сервере ради полутора минут пиковой нагрузки раз в квартал?

Нет — тяжёлая часть работы, обслуживание кеша, не требует мощного сервера, потому что при правильной настройке origin отвечает лишь на единицы запросов в минуту, а не на весь всплеск. Отдельный лендинг на скромном VPS дешевле и безопаснее, чем масштабирование основного продакшена под редкий пик.

CDN сам не прогреется от реальных посетителей за первые секунды?

Прогреется, но с задержкой и через кеш-промах у первых посетителей каждого региона — именно те, кто открыл письмо быстрее всех, получат самый медленный ответ, а при синхронном открытии тысячами это ещё и стадный эффект на origin. Ручной прогрев снимает проблему до того, как её увидят живые люди.

Как отличить сканеры почтовых провайдеров от реальных пользователей в логах?

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

Что если посадочная страница содержит форму регистрации, а не просто статичный контент?

Разделите страницу на статичную оболочку (кешируется целиком и агрессивно) и форму, которая обращается к отдельному лёгкому API-эндпоинту с собственным лимитом запросов — так закешируется большая часть страницы, а лимитом защищена только реально уязвимая часть, пишущая в базу.

На сколько заранее нужно прогревать CDN перед отправкой?

Обычно достаточно 10-15 минут — этого хватает, чтобы прогревающий запрос дошёл до эджей, origin успел ответить и закешироваться, а кеш не успел истечь до реальной отправки. Если TTL на CDN короче, либо увеличьте его для этой страницы, либо прогревайте ближе к моменту отправки.

Рассылка идёт несколькими волнами по сегментам — нужно прогревать каждый раз?

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

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →