ibiza
CPM · CTR …
/

tmax и задержки в RTB: куда уходят миллисекунды

≈ 7 мин чтения · обновлено

tmax — это максимальное время в миллисекундах, которое биржа ждет ответ DSP, считая сетевую задержку в обе стороны. Из этого бюджета DSP получает меньше, чем кажется: часть уходит на передачу по сети, установку соединений, разбор JSON и очереди. Чтобы уложиться, DSP держит постоянные соединения, отвечает с запасом до дедлайна и не ходит в медленные хранилища на горячем пути.

Что говорит спецификация

В OpenRTB 2.5 и 2.6 поле BidRequest.tmax описано как максимальное время в миллисекундах, которое биржа дает на получение ставок, включая интернет-задержку, чтобы избежать таймаута. Значение в запросе важнее любых договоренностей, заключенных заранее.

{
  "id": "auc-7f3a",
  "tmax": 250,
  "at": 1,
  "imp": [{ "id": "1", "bidfloor": 40.0, "bidfloorcur": "RUB",
            "banner": { "format": [{ "w": 320, "h": 50 }] } }],
  "app": { "bundle": "com.example.app" },
  "device": { "os": "android", "ifa": "..." }
}

Главное слово — «включая». tmax отсчитывается на стороне биржи: от момента отправки запроса до момента, когда ответ должен быть у нее. DSP видит запрос позже, а ответ доходит до биржи позже, чем DSP его отправила. Подробнее про само поле — в статье глоссария «tmax».

Из чего складывается задержка

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

Этап Где происходит Пример, мс От чего зависит
Очередь отправки у биржи Биржа 0–5 Нагрузка, пул соединений биржи
Передача запроса Сеть 5–20 Расстояние, маршрут, размер запроса
Установка соединения Сеть 0 или 1–2 RTT Есть ли keep-alive
Прием и разбор запроса DSP 1–3 Размер JSON, распаковка gzip, парсер
Поиск профиля пользователя DSP 1–10 Кеш в памяти или сетевое хранилище
Отбор и оценка кандидатов DSP 1–10 Число кампаний, индексы, модели
Сборка и сериализация ответа DSP 0,5–2 Размер adm, шаблоны
Передача ответа Сеть 5–20 Как и для запроса
Прием ответа биржей Биржа 0–5 Нагрузка на биржу

Если tmax = 250 мс, а сеть в обе стороны занимает 40 мс, у DSP на все остальное остается заметно меньше 210 мс: нужен запас на хвосты распределения.

Сеть: физику не обманешь

Свет в оптоволокне проходит примерно 200 км за миллисекунду. Если сервер DSP в 2 000 км от биржи, теоретический минимум кругового прохода (RTT) — около 20 мс, на практике больше: маршрут не прямой, по пути есть маршрутизаторы. Поэтому серверы ставят ближе к биржам, а не наоборот — время на сеть нельзя «оптимизировать кодом».

Соединение: самая дорогая лишняя работа

Новое HTTPS-соединение требует TCP-рукопожатия (1 RTT) и TLS-рукопожатия (1 RTT в TLS 1.3, 2 RTT в TLS 1.2). При RTT 20 мс это 40–60 мс до первого байта запроса — у короткого tmax они съедают значительную долю бюджета. Спецификация OpenRTB называет постоянные соединения (HTTP keep-alive) одним из самых простых и эффективных способов улучшить производительность: снижаются и накладные расходы, и загрузка процессора на обеих сторонах.

На что смотреть:

  • таймаут простоя соединения у DSP должен быть больше интервала между запросами биржи, иначе соединения будут рваться и пересоздаваться;
  • балансировщик перед DSP тоже держит соединения — его таймауты должны совпадать с настройками сервера;
  • при раскатке новых версий соединения разрываются: штатное завершение (сначала перестать принимать новые, потом дождаться текущих) убирает всплеск таймаутов.

Сжатие

OpenRTB описывает gzip для обоих направлений. Ответ сжимается стандартно: биржа шлет Accept-Encoding: gzip, DSP отвечает с Content-Encoding: gzip. Сжатие запроса включают только по договоренности. Сжатие экономит трафик и время передачи больших запросов, но стоит процессорного времени — для маленьких ответов (например, отказ от ставки) выигрыш может быть нулевым.

Разбор запроса

Bid request в OpenRTB — JSON на несколько килобайт с вложенными объектами imp, app/site, device, user, а также расширениями ext. Типичная ошибка — разбирать одни и те же вложенные поля по нескольку раз на разных этапах. Разобрать один раз, сохранить в структуру и передавать дальше — дешевая оптимизация.

Отказ от ставки — тоже ответ

Спецификация предлагает два способа сказать «не ставлю»: пустой ответ с HTTP 204 или объект BidResponse с кодом причины в поле nbr. Быстрый отказ полезен всем: биржа не ждет до дедлайна, а DSP не тратит ресурсы на запросы, которые все равно не купит.

HTTP/1.1 204 No Content

Ранний отказ стоит делать на дешевых проверках: неподдерживаемый формат, запрещенное приложение, флор выше максимальной ставки всех активных кампаний.

Что делает DSP, чтобы уложиться

  1. Собственный дедлайн. DSP считает время от получения запроса и отвечает до tmax минус запас на обратную сеть. Если какой-то этап не успел, ставка собирается из того, что есть, или отправляется отказ — но вовремя.
  2. Все горячее — в памяти. Кампании, креативы, таргетинги и правила ставок лежат в памяти процесса и обновляются в фоне. В сетевое хранилище на горячем пути идет только то, что нельзя держать локально, например профиль пользователя.
  3. Короткие таймауты на зависимости. Каждое обращение к внешнему хранилищу ограничено по времени. Медленный ответ хранилища не должен превращаться в медленный ответ бирже.
  4. Параллельные запросы. Независимые поиски (профиль, частотные ограничения, сегменты) выполняются одновременно, а не по очереди.
  5. Индексы вместо перебора. Кандидаты отбираются по заранее построенным индексам (формат, гео, ОС), а не перебором всех кампаний.
  6. Защита от перегрузки. При нехватке ресурсов лучше быстро отказаться от части запросов, чем отвечать на все с опозданием: опоздавший ответ стоит ресурсов и ничего не приносит.
  7. Без лишней работы в ответе. Тяжелое логирование, запись аналитики и отправка событий — асинхронно, после того как ответ ушел.

Отдельный случай — запросы с несколькими показами (imp) или с несколькими форматами в одном показе. Работа по отбору кандидатов растет с их числом, и такие запросы чаще упираются в дедлайн. Ограничить число оцениваемых вариантов на запрос надежнее, чем надеяться, что их будет мало.

Как измерять задержки

Среднее время ответа почти бесполезно: аукцион проигрывают на хвостах. Смотрят перцентили — p50, p95, p99 — и их нужно смотреть раздельно:

Метрика Где снимается Что показывает
Время обработки в DSP Внутри сервиса Код, хранилища, сборщик мусора
Время на балансировщике Вход в инфраструктуру DSP Очереди и соединения до кода
Доля таймаутов у биржи Отчет биржи, коды проигрыша 2 То, что видит покупатель на самом деле
Число новых соединений в секунду Балансировщик, сервер Работает ли keep-alive

Если внутренний p99 комфортный, а биржа видит таймауты, проблема почти всегда снаружи кода: сеть, соединения, балансировщик, очереди перед приложением. Причины проигрыша и то, как их читать, разобраны в статье «Почему я проиграл аукцион».

Пример: как распределить 250 мс

Пусть биржа шлет tmax = 250 мс, RTT до нее — 25 мс.

Статья бюджета мс
Доставка запроса (половина RTT) ~13
Доставка ответа (половина RTT) ~13
Запас на очереди и разброс сети 40
Внутренний дедлайн DSP 150
Резерв ~34

Внутри 150 мс DSP закладывает лимиты на каждую зависимость (например, по 10–20 мс на сетевые хранилища) и прерывает обработку по дедлайну. Если без keep-alive каждое соединение стоит еще 50 мс на рукопожатия, резерв уходит в ноль — и это видно в отчете биржи как рост проигрышей с кодом 2.

Почему таймауты растут внезапно

Если код не менялся, а доля опозданий выросла, причина обычно в одном из пяти мест.

Симптом Вероятная причина Как проверить
Таймауты растут волнами в часы пик Не хватает ресурсов: процессор, потоки, соединения к хранилищам Загрузка процессора и очередь запросов на пиках
Всплески каждые несколько минут Паузы сборщика мусора или фоновые перезагрузки данных Корреляция пауз с временем всплесков
Рост после раскатки Обрыв постоянных соединений, «холодные» кеши новых экземпляров Число новых соединений в секунду в момент раскатки
Рост только у одной биржи Сеть до этой биржи или изменение ее tmax Сравнить tmax в запросах и RTT до биржи
Медленно растущий хвост p99 Увеличились данные: больше кампаний, тяжелее профили, больше JSON Размер запроса и число кандидатов на запрос

Полезная привычка — логировать tmax из каждого запроса вместе с фактическим временем обработки. Тогда видно не только «сколько мы тратим», но и «сколько нам дали», а изменение условий на стороне биржи не путается с деградацией своего кода.

Как задержка связана с деньгами

Опоздавшие ответы не дают показов, но съедают ресурсы — процессор, сеть, обращения к хранилищам. В воронке RTB они выглядят как разрыв между «ставок отправлено» и «ставок учтено биржей». Если доля таймаутов растет, падают и выигрыши, и win rate, хотя ставки и креативы не менялись. Поэтому мониторинг задержек — часть закупки, а не только эксплуатации.

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

Что важнее: tmax из запроса или договоренность с биржей?

Значение из запроса: оно важнее любых предварительных договоренностей. Поле BidRequest.tmax — максимальное время в миллисекундах, которое биржа ждет ставки, включая задержку сети.

Пришлет ли биржа уведомление, если ответ DSP опоздал?

Не обязательно. Опоздавший ответ не участвует в аукционе; биржа может прислать уведомление о проигрыше с кодом 2 (Impression Opportunity Expired) или не прислать ничего.

Почему keep-alive так важен для RTB?

Новое TCP+TLS-соединение стоит одного-двух круговых проходов по сети до первого байта запроса. С постоянными соединениями эта цена платится один раз, а не на каждом аукционе.