Система работала идеально. И это была проблема: почему иногда нужно тормозить систему, которая может быстрее
Представьте: вы смотрите финал чемпионата по телевизору, напряжение нарастает, и вдруг — за секунду до того, как мяч пересекает линию ворот, на телефоне всплывает уведомление: «ГОЛ!». Поздравление, которое вы ещё не должны были получить. Эмоции испорчены, магия момента разрушена. Пользователь злится на приложение и отписывается от уведомлений.
Это не гипотетическая ситуация. Это реальная проблема, с которой столкнулся Данил Редько — software engineer, строящий инфраструктуру для платформ профессиональных спортивных команд. В его задачи входило обеспечить доставку миллионов уведомлений за секунды. Система работала идеально, но именно идеальность стала проблемой: уведомления приходили быстрее, чем телевизионная трансляция, превращаясь в спойлеры. Его инфраструктура должна выдерживать нагрузку, которая возрастает в 50 раз за секунды, и при этом оставаться незаметной.
Потому что лучшая работа инженера — та, которую не замечают.
В этом интервью Данил расскажет, почему иногда инженеру приходится искусственно замедлять систему, как сегментация пользователей спасает от неловких ситуаций и что важнее — скорость или правильный момент.
— Данил, вы строите системы, которые должны работать, когда ими пользуются все одновременно. Что это значит на практике?
— Представьте: обычный день, платформа работает спокойно. А потом начинается финал чемпионата. За секунды количество пользователей вырастает с нескольких тысяч до десятков миллионов. Нагрузка возрастает в 10–50 раз. И система не имеет права «лечь».
Для инженера это, как если бы в обычный торговый центр вдруг одновременно зашли все жители города. Лифты, эскалаторы, кассы — всё должно выдержать. Только в нашем случае «касса» — это сервер, который должен отправить миллионы уведомлений за секунды.
— Вы работали над системами real-time уведомлений для крупных спортивных платформ. Кажется, что задача предельно простая: сделать так, чтобы уведомления приходили как можно быстрее. Но вы столкнулись с парадоксом: слишком быстро — это плохо. Расскажите, как это может быть?
— Действительно, парадокс. Я работал в компании, у которой были клиенты — спортивные команды в разных лигах, и мы брали уведомления из API лиг и отправляли их пользователям конкретной команды (фанатам наших клиентов). В пиковые моменты — например, финальные матчи — система должна была доставлять миллионы уведомлений на одно событие. Технически мы добились впечатляющих показателей: события обрабатывались за 200–500 миллисекунд, fan-out (рассылка по подписчикам) занимал ещё 100–300 миллисекунд, и первые уведомления уходили пользователям меньше, чем через секунду.
Но однажды мы с командой были на стадионе. Через пару секунд после тачдауна наши телефоны завибрировали — уведомление уже пришло. И тут я понял: для тех, кто смотрит матч по телевизору, это катастрофа. Телевизионная трансляция идёт с задержкой 15–30 секунд, стриминг — 10–60 секунд. Получалось, что наше идеально быстрое уведомление превращалось в спойлер. Пользователь, который ещё не видел гола на экране, узнавал о нём от приложения. И реакция была предсказуемой: люди злились и отписывались от уведомлений.
— То есть ваша система работала «слишком хорошо» с технической точки зрения, но проигрывала с продуктовой. Как вы решали эту проблему?
— Первым побуждением было, наверное, ничего не менять — ведь скорость доставки — это классическая метрика качества. Но я предложил добавить искусственную задержку. Мы проанализировали, какую задержку вносят разные источники трансляции: ТВ, стриминговые платформы, социальные сети. И выбрали фиксированную задержку около 30 секунд — чтобы уведомления гарантированно не опережали самый медленный из популярных каналов.
Но тут возник новый нюанс: пользователи, которые находятся на стадионе, видят событие в реальном времени. Для них задержка в 30 секунд была бы уже странной — они получали бы уведомление о том, что произошло полминуты назад. Здесь помог опыт сегментации. Мы знали, кто из пользователей находится на стадионе (например, через сканирование билетов или геолокацию), и просто не отправляли им такие уведомления вовсе. Или отправляли без задержки, но с пометкой «на стадионе».
— Получается, что решение включало не только техническую задержку, но и сложную логику сегментации. А как вы проверяли, что это действительно улучшает опыт пользователей?
— Мы смотрели на ключевую метрику — отписки от уведомлений. До внедрения задержки пользователи массово отписывались, и одной из причин были именно спойлеры. После того как мы добавили задержку и сегментацию, метрика отписок стабилизировалась и даже немного снизилась. То есть пользователи перестали воспринимать уведомления как источник раздражения.
Но важно отметить, что мы не просто «затормозили» систему. Мы добавили гибкости: в настройках пользователь мог выбрать «Мгновенные уведомления (спойлеры возможны)» или «Без спойлеров (с задержкой)». Активные фанаты, которые и так смотрят матч, могли выбрать второй вариант, а те, кто не может смотреть игру, — первый.
— В вашем описании есть ещё один интересный момент — архитектурная сложность. Миллионы уведомлений за секунды — это звучит как настоящий вызов. Расскажите немного о том, как устроена такая система «под капотом».
— Да, это действительно сложная инженерия. Цепочка выглядит примерно так: событие (например, гол) поступает в систему — это ingestion. Потом валидация (убедиться, что это действительно гол, а не ложное срабатывание). Затем маршрутизация: нужно понять, каким пользователям отправлять уведомление, на каких языках, с каким текстом. Дальше самый тяжелый этап — fan-out, когда система «размножает» уведомление на миллионы подписчиков и отправляет через push-провайдеров (APNS для iOS, FCM для Android). Каждое звено добавляет задержку, и наша задача — уложиться в доли секунды.
Мы использовали очереди на базе Kafka, предварительное вычисление подписок (чтобы не делать это в реальном времени), горизонтальное масштабирование воркеров, дедупликацию событий (чтобы одно и то же уведомление не ушло дважды) и приоритизацию: гол важнее, чем жёлтая карточка, а жёлтая карточка важнее замены. Если система начинает захлёбываться, она сначала отбрасывает менее важные события.
— И всё это происходит незаметно для пользователя. Он просто видит уведомление в нужный момент. Это напоминает знаменитую фразу о том, что лучший интерфейс — тот, который не замечаешь.
— Абсолютно. Пользователь не видит очередей, ретраев, rate limits, борьбы за миллисекунды. Он видит только результат: «Пришло вовремя» — значит, продукт качественный; «Опоздало» или «Пришло слишком рано» — продукт плохой. Чем лучше система работает, тем меньше её замечают. Это и есть невидимая сложность.
Для меня этот опыт стал важным сдвигом в мышлении. Раньше я смотрел на задачи чисто технически: как сделать быстрее, надёжнее, масштабируемее. А теперь я всегда задаю себе вопрос: а как это воспримет пользователь? В системах такого масштаба инженер должен быть немного психологом.
— Сейчас вы работаете над встраиванием искусственного интеллекта в рабочие процессы крупных международных компаний. Этот опыт — с задержками и сегментацией — как-то повлиял на ваш подход к новым задачам?
— Безусловно. ИИ-системы тоже часто грешат тем, что технически работают великолепно, но в реальном использовании раздражают пользователя. Например, чат-бот, который отвечает мгновенно, но невпопад. Или рекомендательная система, которая предлагает очевидные вещи. Сейчас я больше внимания уделяю продуктовому контексту: как именно пользователь будет взаимодействовать с результатом работы ИИ, в какой момент, с каким ожиданием. Иногда искусственная задержка или «пауза» перед ответом делает взаимодействие более естественным.
— Если подводить итог, какой главный урок вы вынесли из работы над системами real-time уведомлений?
— Самый главный урок: техническое совершенство не всегда равно идеальному пользовательскому опыту. Иногда нужно сознательно ограничивать систему, чтобы она работала не быстрее всех, а в правильном ритме. Инженер должен понимать не только то, как работает код, но и то, как живёт пользователь. В спортивных приложениях это означало: не гнаться за миллисекундами, а синхронизироваться с трансляцией. И это решение принесло больше пользы, чем любая оптимизация.