Как мы запустили стартап и выжили

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

Все началось, как стартап. Рост пошел не так гладко, как хотелось бы — бизнес привлекал партнеров довольно быстро, но из-за лагов соединения с ними нагрузка оказалась много выше расчетной. Считайте это “ошибкой выжившего”, но мы отложили оптимизацию и быстро масштабировали железо, что позволило нам удержаться на рынке. Сейчас все это позади, но благодаря такому решению проект все-таки дожил до преобразований архитектуры. Сейчас эти преобразования идут полным ходом, параллельно с дальнейшим развитием решения.

Схема работы AdExchange Server

Схема работы AdExchange Server

Что за проект?

Совместно с партнерами из Румынии мы работаем над созданием и совершенствованием Push Advertising Network.

Идея проекта заключается в заработке на рекламном трафике за счет его “обогащения”. Мы помогаем площадкам показывать более “дорогую” рекламу, выбираем из множества объявлений те, на которые посетитель сайта скорее откликнется.

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

Наше решение состоит из двух подсистем:

  • AdExchange Server;
  • Campaign manager.

AdExchange Server

Фактически это аукцион.

С партнерского ресурса (SSP) к нам приходит http-запрос на показ рекламы. Мы в свою очередь запрашиваем подходящую под запрос рекламу у множества DSP-партнеров (поставщиков рекламы), после чего внутри AdExchange сервера между полученными объявлениями проходит аукцион. Выигрывает оптимальная по стоимости и параметрам ставка, соответствующее которой объявление и уходит в SSP.

На этой схеме CM - наш собственный менеджер кампаний, который участвует в аукционе наряду с другими DSP.

На этой схеме CM — наш собственный менеджер кампаний, который участвует в аукционе наряду с другими DSP.

Более детально о логике работы аналогичного сервера мы рассказывали в одной из предыдущих статей. Также ранее мы писали о том, как реализовывали AdExchange в соответствии с требованиями GDPR.

Campaign manager

Менеджер кампаний (Campaign manager) выступает одним из внешних партнеров (DSP) для AdExchange сервера. Он дает рекламодателям возможность заказать показ своей рекламы прямо на нашей площадке через личный кабинет. Для этого достаточно создать кампанию (креатив и текст) и настроить ее параметры — аудиторию, стоимость и т.п., которые определяют, как именно сервис будет реагировать на запросы из AdExchange. Также личный кабинет позволяет просматривать аналитику по ранее запущенным кампаниям: какие объявления были показаны, по каким из них клиент перешел. Те же сервисы доступны рекламодателям через внешнее API.

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

Две части проекта взаимодействуют друг с другом, но уже некоторое время разрабатываются разными командами. Общими остаются тестировщики, devops и технический директор.

Все началось со стартапа…

Проект мы начали развивать в ноябре 2019 года. На тот момент в команде был всего один бэкендер — коллега у него появился только через месяц. В две головы проект разрабатывался около трех месяцев.

MVP с урезанным функционалом представили партнерам в марте 2020. Все получилось довольно быстро, потому что у нас уже был опыт в разработке подобных систем. Нужно было только адаптировать этот опыт под актуальные требования.

К моменту запуска MVP в команде появился еще один человек — на фронтенде.

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

Проектируя MVP, мы предполагали одну нагрузку и под нее строили нагрузочное тестирование, а по факту увидели совсем иную историю. Уже работая с несколькими DSP-партнерами, мы уперлись в то, что их сервера отвечали не всегда оперативно. Одни хорошо поддерживали стабильное соединение, а другие его постоянно разрывали. Все это давало дополнительную нагрузку на наш сервер — по примерным оценкам ошиблись мы раза в два. Поэтому нам практически сразу пришлось увеличивать количество серверов.

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

Когда нагрузка на продукт активно растет, у тебя есть два пути: оптимизировать архитектуру или докупать сервера.

Оптимизация логична с точки зрения перфекциониста. Но она требует времени и человеческих ресурсов. Ни первого, ни второго на той стадии у нас не было. Не выйдешь же на базарную площадь с запросом: “Два человека на кирпичный завод!”. Людей надо найти, а потом ввести в проект, который состоит вовсе не из 5 строчек кода. На таких масштабных проектах первые две недели новичок (senior) будет притормаживать всю разработку, потому что ему придется что-то объяснять и рассказывать. Реальную пользу проекту он начнет приносить еще позже.

Все это время нам нужно было держать нагрузки, поэтому оптимизацию немного отложили. Нужно было выжить в этом конкурентном мире — встать на более-менее накатанные рельсы.

На этом этапе мы старались удовлетворить только обязательным требованиям бизнеса — сначала реализовывали то, без чего решение в принципе не запустится, потом только основной функционал. Когда начали подключать партнеров, добавилась работа по адаптации каждого из них. Конечно, существуют общие форматы обмена данными (OpenRTB, например), но в реальности оказалось проще под каждого настраивать взаимодействие. А это тоже время.

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

Когда проект уже более-менее стабилизировался, мы начали оптимизацию. Часть функционала изначально реализовали не идеально — в соответствии с первоначальными потребностями. Условно говоря, сначала нужно было строить простые отчеты. Это позволило быстро стартовать. Но со временем пришло время более полно удовлетворять бизнес-требованиям. Простые отчеты мы начали заменять более сложными. В старой парадигме так расширить функционал было уже нельзя — все работало бы гораздо медленнее или нестабильно, поэтому начали править все, вплоть до архитектуры. Одним словом, занялись техническим долгом.

В контексте отчетов мы перешли с батчевой обработки на Postgres на Kafka Streams, а впоследствии на аналитическую систему на базе Clickhouse. Kafka Streams — в целом неплохое решение, но не под нашу задачу. О том, с чем пришлось столкнуться, мы уже рассказывали в статье. В итоге мы перешли на более специализированный инструмент для работы со статистикой. Этот переход был неизбежен, потому что раньше мы каждое новое требование по агрегации и анализу данных реализовывали по две-три недели. Сначала настроить сбор нужных агрегатов, потом их обработать. А Clickhouse позволил просто сваливать весь трафик в одну базу и получать не сотни терабайт, а всего 1.5 Тб в день. Он фантастически все сжимает и быстро делает Select-ы на этих объемах за счет множества встроенных механизмов оптимизации. И теперь требования бизнеса по созданию нового отчета на основе сырых данных можно реализовывать менее чем за день.

Выше речь шла в основном о работе над AdExchange сервером. Разработка менеджера кампаний (Campaign Manager) стартовала с появления в команде фронтендера. Эта задача уже была для нас принципиально новой, так что тут мы двигаемся медленнее, больше внимания уделяя фронтенду, в частности, интерфейсу как таковому. Кроме того, перед запуском менеджера кампаний пришлось поработать над антифрод системой — улучшить трафик.

Campaign Manager также прошел стадию расширенного MVP. Сейчас работаем над багами. Параллельно, пока команда AdExchange занимается оптимизацией кода, здесь мы оптимизируем пользовательский experience.

Проект сегодня

Сейчас у нас на продакшене 59 довольно мощных серверов.

Эти сервера получают около 100 тыс. http-запросов в секунду. Анализируя и обрабатывая каждый запрос, внутренние процессы создают собственную нагрузку. Охарактеризовать ее можно следующими цифрами:

  • в таблицы Clickhouse заливается около 170 тыс. записей в секунду, каждая из которых содержит 130 полей;
  • в сутки — это около 15 млрд записей или 1.5 Тб данных, которые используются для формирования бизнес-отчетности, фильтрации и сортировки.

На 86,7% код AdExchange сервера написан на Kotlin. Остальной код — Java, который остался от первых версий системы. Возможно, в будущем мы его тоже перепишем на Kotlin.

Менеджер кампаний разрабатывает другая часть команды, используя тот же Kotlin (100%). Фронт Campaign Manager — TypeScript и React.

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

Приходите на этот проект — у нас интересно!

Наши статьи по теме:

Все статьи

Связаться с нами

Мы свяжемся с вами в течение 24 часов.