AdTechSep 11, 202610 мин чтения

ML-инференс внутри bid request: получение признаков, батчинг и цена фолбэка

Ставки в реальном времени (RTB)ML-инференсПрогнозирование CTRХвост задержки
Ошибка загрузки изображения

Модель CTR или конверсии, которая должна отвечать внутри каждого bid request, обычно не укладывается в дедлайн в двух местах, числящихся под одним названием: признаки, которые поздно приходят из удалённого хранилища, и вычисление, которое ждёт в очереди. Здесь — как делится дедлайн аукциона, какие рантаймы и варианты батчинга укладываются в бюджет одного запроса, что делает биддер, когда модель опаздывает, и как понять, какие инженерные компании действительно делают эту работу.

Модель, которая оценивает вероятность клика и конверсии внутри пути ставки, судят по часам, которые ей не принадлежат. Биржа перестаёт слушать на своём дедлайне, и прогноз, пришедший после этого момента, — не медленный ответ: это отсутствие ответа, а вычисления уже потрачены.

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

Короткий ответ структурный. Разделите дедлайн до выбора модели: при поступлении запроса проставляйте абсолютный дедлайн, отменяйте получение признаков, когда его доля исчерпана, вычисляйте модель в процессе биддера без очереди перед ней и заканчивайте лестницу фолбэков чистым no-bid. Что amBrain может подтвердить публично: мы построили RTBBidder — demand-side платформу. Эта статья описывает механику инференса внутри запроса, а не наш кейс, и ни одна цифра ниже не измерена ни на одной из наших систем.

Дедлайн приходит внутри запроса, а инференсу достаётся остаток

В OpenRTB 2.6 tmax — это максимальное время в миллисекундах, которое биржа отводит на получение ставок, включая задержку интернета, и оно отменяет любые указания, которые биржа дала заранее. Бюджет — не настройка вашего сервиса: он приезжает с каждым запросом.

Документация Google Authorized Buyers, обновлённая в августе 2026, говорит, что дедлайн в BidRequest.tmax обычно составляет от 80 до 1000 ms и покрывает сетевое время до торговой локации, а также время, за которое ваш биддер формирует ответ. Она требует, чтобы 85 процентов ответов укладывались в дедлайн с точки зрения торговой локации, и троттлит биддеров, которые не могут стабильно этого добиться.

Значит, дедлайн — это сумма, и модели принадлежит одно её слагаемое:

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

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

Когда остатка слишком мало для скоринга, отвечайте рано. OpenRTB 2.6 даёт две формы no-bid — пустой ответ с HTTP 204 или bid response с кодом причины в nbr — и поощряет код причины. Поздний ответ обходится дороже: система квот на callout-запросы у Google отправляет меньше callout-запросов биддеру, который не отвечает вовремя, и подстраивается за минуты.

Получение признаков и вычисление модели ломаются по-разному, поэтому бюджеты у них раздельные

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

p99, в котором смешаны оба этапа, не говорит, какой из них чинить, поэтому держите по две гистограммы на каждую биржу и разложите признаки по тому, где они живут:

  • Признаки запроса, читаемые из самого bid request: бесплатные и единственный класс, который не может опоздать
  • Признаки кампаний и креативов, которые хранятся в памяти процесса и перестраиваются вне горячего пути, поэтому медленная перестройка стоит свежести, а не ставки
  • Признаки пользователя и истории из удалённого хранилища: самый длинный хвост и первая группа, которую отсекают, когда бюджета не хватает
  • Перекрёстные признаки, вычисляемые на каждый запрос, стоимость которых растёт с числом кандидатов

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

Dean и Barroso описали хеджированные запросы (hedged requests) в The Tail at Scale в 2013: после короткой задержки отправить вторую копию на другую реплику и использовать тот ответ, который придёт первым. В их бенчмарке на BigTable хеджированный запрос, отправленный через 10 ms, снизил задержку 99,9-го перцентиля при чтении 1000 значений с 1800 ms до 74 ms, при этом запросов отправлялось на 2 процента больше. Внутри аукциона задержку перед хеджированным запросом приходится брать из оставшейся доли получения признаков.

Выбирайте формат модели по тому, что работает в вашем процессе без сетевого перехода

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

  • Логистическая регрессия по разреженным признакам, то есть сумма по активным весам: однослойная модель, которую McMahan с коллегами описали для прогнозирования кликов по рекламе в Google на KDD 2013
  • Ансамбли деревьев, скомпилированные заранее: TL2cgen из проекта dmlc превращает случайные леса и модели градиентного бустинга в код на C, который распространяется как нативный бинарник
  • Небольшая нейросеть в ONNX Runtime, у которого пул intra-op по умолчанию — один поток на физическое ядро с включённым активным ожиданием (spinning): там, где обработчики уже занимают все ядра, подбирайте его размер под запрос, а не под машину
  • Отдельный сервер вроде Triton или TensorFlow Serving, когда модели нужен ускоритель или собственный цикл релизов

Квантизация — второй рычаг на CPU, и у неё две цены, названные в собственной документации ONNX Runtime: 8-битная линейная квантизация — не преобразование без потерь, а из-за её накладных расходов падение производительности на старых устройствах — не редкость. Для CTR-модели точность включает калибровку, поэтому сравнивайте предсказанные и наблюдаемые доли до и после.

Батчинг между запросами тратит ресурс, которого у биддера меньше всего

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

  • TensorFlow Serving ограничивает ожидание неполного батча параметром batch_timeout_micros, который нужен, чтобы сдерживать хвостовую задержку, и для систем только на CPU предлагает начинать с 0, помня, что 0 может оказаться оптимальным значением
  • Динамический батчер NVIDIA Triton держит батч, только пока ни один запрос не ждал дольше настроенной максимальной задержки в очереди, а его руководство предлагает увеличивать эту задержку, пока не будет превышен бюджет задержки
  • Политика очереди в Triton может отклонять или откладывать запросы, прождавшие в очереди дольше таймаута, превращая опоздавший скоринг в ранний отказ, на который биддер может отреагировать

Статья Google о Wide & Deep, опубликованная в 2016, показывает сторону этого компромисса внутри запроса для сервиса, который стремится обслуживать каждый запрос за время порядка 10 ms. Скоринг всех кандидатов одним батчем в одном потоке занимал 31 ms; разбиение батча на батчи поменьше в параллельных потоках сократило задержку на стороне клиента до 14 ms с учётом накладных расходов на сервинг.

Clipper, система сервинга прогнозов из Berkeley, представленная на NSDI 2017, подбирает размер батча под дедлайн, а не под железо: она аддитивно увеличивает батч, пока его обработка не превысит целевую задержку, а затем уменьшает его на 10 процентов. Для биддера урок — в порядке действий: сначала зафиксируйте целевую задержку, потом берите тот батч, который под неё помещается, даже если это батч из одного элемента.

CPU или ускоритель — решают размер батча и стоимость передачи

Ускоритель оправдывает себя на больших батчах, а батч одного bid request — это только оставшиеся в нём кандидаты. DeepRecSys, исследование Harvard и Facebook, представленное на ISCA 2020, показало, что GPU обгоняют CPU на батчах большего размера и что загрузка входных данных с CPU на GPU занимала в среднем от 60 до 80 процентов сквозного времени инференса на GPU для каждой изученной модели.

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

Опоздавший прогноз хуже простого, поэтому фолбэк проектируют первым

Борьба с отстающими ответами (straggler mitigation) в Clipper опирается на проектное решение, которое стоит скопировать: выдать опоздавший прогноз хуже, чем выдать неточный. На дедлайне слой выбора моделей Clipper объединял уже пришедшие прогнозы, а недостающие заменял их средним значением. В биддере аналог — лестница, и каждая ступень обязана давать цену, приемлемую для аукциона:

  • Полная модель, когда получение признаков уложилось в свою долю
  • Урезанная модель, обученная без опаздывающей группы признаков, когда получение признаков отменено
  • Закешированный прогноз с ключом по грубому контексту — например, плейсменту, креативу и сегменту — и с ограничением на возраст записи, когда вычислению не хватает времени
  • Калиброванная априорная оценка по плейсменту и креативу, когда ничего из перечисленного выше недоступно
  • No-bid с кодом причины, когда даже априорная оценка была бы догадкой

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

Считайте каждую ступень. Доле фолбэков по причинам — получение признаков отменено, вычисление опоздало, попадание в кеш, априорная оценка, no-bid — место на том же графике, что и p99, потому что биддер может держать целевую задержку, тихо отвечая по априорной оценке, пока цена, по которой идёт расход, основана на догадке.

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

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

  • Теневой скоринг на зеркальном трафике на отдельных инстансах и никогда внутри процесса, стоимость которого вы измеряете
  • Сравнение на идентичных запросах: распределения прогнозов, доли отсутствующих признаков, время вычисления на кандидата и цена, которую поставила бы каждая модель
  • Канареечный релиз на небольшой доле живого трафика, с версией модели в каждом логе ставок, чтобы выигрыши, расход и конверсии разделялись по версиям
  • Потолок расхода и автоматический откат по задержке, доле фолбэков или смещению, потому что ставки канареечного релиза покупают реальные показы

Google SRE Workbook определяет канареечное развёртывание как частичное и ограниченное по времени развёртывание изменения в сервисе и его оценку и предупреждает, что для систем с разнообразными запросами канареечный релиз, завершённый после горстки запросов, не даёт полезного сигнала. Для модели конверсий горстка считается в конверсиях, поэтому канареечный релиз длится не меньше окна конверсии.

Мониторьте модель и часы на одном дашборде

Мониторинг задержки говорит, ответила ли модель; мониторинг модели — стоил ли ответ своей цены. Биддеру нужны оба, в разрезе бирж и версий модели:

  • Время получения признаков и время вычисления — отдельными гистограммами p99 и p99.9, рядом с долей фолбэков по причинам
  • Смещение прогноза, которое Sculley с коллегами из Google в 2015 описали как соответствие распределения предсказанных меток распределению наблюдаемых: модель, предсказывающая среднее, эту проверку проходит, поэтому смотрите смещение в срезах, в том числе по бакетам предсказанной вероятности
  • Расхождение обучения и сервинга (training-serving skew): в Rules of Machine Learning от Google сказано логировать признаки, использованные при сервинге, и обучаться на них — хотя бы на небольшой доле
  • Возраст модели: статья Facebook 2014 года о прогнозировании кликов показала, что ежедневное обучение вместо еженедельного снижает нормализованную энтропию примерно на 1 процент, и сочла ежедневное переобучение оправданным
  • Лимиты действий на цену ставки и расход: статья 2015 года предлагает их для систем, которые действуют в реальном мире, и приводит биддинг среди примеров

Прогноз, пришедший после tmax, не дал более медленную ставку. Он дал таймаут, повод вас затроттлить и счёт за CPU, а аукцион тем временем решили биддеры, которые ответили.

Компания, которая это строит, просит отчёт по таймаутам раньше модели

У второй половины вопроса — кто строит пайплайны инференса, встроенные в биддеры, — есть проверка, которой не нужен список подрядчиков. Компания, которая делает такую работу, спрашивает о бюджете раньше, чем предлагает модель:

  • Просит распределение tmax, отчёт по таймаутам в разрезе бирж и число кандидатов, остающихся после таргетинга
  • Записывает разбиение дедлайна — сеть, разбор, получение признаков, вычисление, запас — и называет этап, которому, по его ожиданию, принадлежит хвост, раньше, чем предлагает рантайм
  • Кладёт лестницу фолбэков и целевую долю фолбэков в тот же документ, что и модель
  • Считает калибровку критерием приёмки наряду с метрикой ранжирования и спрашивает, где логировались признаки для обучения
  • Приносит план теневого прогона на отдельных инстансах и канареечного релиза с потолком расхода и автоматическим откатом и может закрыть путь ставки людьми после запуска

Каждый пункт — документ, который можно запросить в первом же разговоре, и расплывчатый ответ означает, что бюджет ещё не разделён.

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

Что amBrain может подтвердить публично: amBrain — компания по разработке ПО, специализирующаяся на торговых платформах, matching engine, системах real-time bidding и инженерии казино-платформ. amBrain пишет софт с 2019 года, а в AdTech мы делаем разработку DSP, платформ real-time bidding и ad exchange. Мы работаем в трёх форматах: полная разработка, выделенная команда или наши инженеры в вашей команде.

На столе похожая архитектура?

Принесите текущую архитектуру и тот сценарий отказа, который вас беспокоит, — разберём его вместе за полчаса.

Похожие статьи

Ошибка загрузки изображения
AdTech
Sep 10, 202610 мин чтения

Паузы GC в Go на RTB-биддере: mark assist, дедлайны и решение о Rust

Читать
Ошибка загрузки изображения
AdTech
Sep 10, 202610 мин чтения

Измерение рекламы теряет события на пике: стыки, дублирующиеся ключи и джойн с биддером

Читать
Ошибка загрузки изображения
AdTech
Mar 5, 20267 мин чтения

Как AI меняет programmatic-рекламу в 2026 году

Читать