• backend

Инженерия надёжности в Маркете: принципы, процессы и реальные кейсы

Для такого гиганта электронной коммерции, как Яндекс Маркет, надёжность — это не просто техническая характеристика. Это воздух, которым дышит бизнес. Если сайт или приложение перестают работать, если пользователь не может найти товар или оформить заказ — компания теряет деньги и, что ещё важнее, доверие клиентов. Секунды простоя могут стоить миллионы, а репутационные потери могут оказаться невосполнимыми. Как же обеспечить эту жизненно важную стабильность в условиях постоянно растущих нагрузок и непрерывных изменений?

Представьте себе сложнейший механизм, состоящий из сотен внутренних IT-систем и более тысячи микросервисов, как это устроено в Маркете. Все они тесно связаны друг с другом. Один запрос пользователя на сайте может порождать сотни, а то и тысячи запросов внутри этой экосистемы. Сбой даже в одном, казалось бы, незначительном компоненте может запустить цепную реакцию и нарушить основной пользовательский сценарий — возможность найти, выбрать и купить товар. При этом сама система не статична: код постоянно обновляется, запускаются новые маркетинговые акции, меняется поведение пользователей.

Как в такой динамичной и сложной среде поддерживать работоспособность 24/7? Как готовиться к пиковым нагрузкам, которые могут вырасти в разы? И как быстро реагировать, если что-то всё-таки пошло не так? В этой статье мы попробуем посмотреть за кулисы Яндекс Маркета и разберёмся, на каких принципах строится его надёжность, какие процессы и инструменты используются для её обеспечения, и с какими реальными вызовами сталкивается команда, отвечающая за стабильность одного из крупнейших маркетплейсов страны.

От пиковых сезонов к «вечной» распродаже

Ещё несколько лет назад мир онлайн-ритейла в России жил по довольно предсказуемым циклам. У нас, как и у многих, были чётко выраженные «сезоны» — периоды пиковых нагрузок, к которым мы целенаправленно готовились. Вспомните: Чёрная пятница, пришедшая с Запада, День холостяка из Китая, наши гендерные праздники. Этих скидок люди действительно ждали.

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

Но за последние пару лет ситуация кардинально изменилась. Это забавно, но само понятие «сезона» для нас практически исчезло. Почему? Во-первых, объем онлайн-торговли значительно увеличился — его темпы роста в 2024 году составили 40% по данным Минпромторга РФ. Во-вторых, основные игроки рынка перешли в режим постоянной «войны за пользователя». Бесконечные акции, скидки — всё это стало нормой.

Представьте себя на месте покупателя. Ещё года четыре-пять назад вы действительно ждали Чёрную пятницу, чтобы купить что-то крупное дешевле. А сейчас? Мелкие распродажи идут практически каждые две недели. Если не на одном маркетплейсе, так на другом. Постоянно где-то есть скидки. Ждать особого повода уже нет смысла.

01 (5).png

К чему это привело с точки зрения надёжности? Пиковые нагрузки стали не такими экстремальными. Да, наша служба доставки и операционные сервисы в такие дни всё ещё работают с повышенным напряжением, обрабатывая возросший объём заказов, особенно в регионах. Но для IT-инфраструктуры эти пики стали более сглаженными.

Казалось бы, службе надёжности стало легче? Отчасти да. Но эта равномерность нагрузки потребовала изменить сам подход к подготовке. Если раньше мы перед сезоном на три месяца ощутимо сдвигали фокус с продуктовой разработки на технический долг, чтобы усилить надёжность, то сейчас мы перешли к модели, когда вкладываем время и ресурсы в стабильность систем равномерно в течение всего года. Традиция сезона как периода повышенного внимания осталась, но теперь это не спринт, а скорее марафон, который мы бежим постоянно.

Философия и архитектурные принципы: Как строить устойчивые системы

Когда у тебя под капотом полторы тысячи IT-сервисов, как в Маркете, и один запрос пользователя может превращаться в сотни внутренних реквестов, просто «писать хороший код» недостаточно. Нужна чёткая философия и набор архитектурных принципов, которые позволяют системе оставаться на плаву даже в самых сложных ситуациях.

Главный принцип, которым мы руководствуемся при проектировании, — это graceful degradation, или «изящная деградация». Звучит, может, не очень оптимистично, но суть проста: деградируй, но продолжай работать. Система должна уметь жертвовать второстепенным функционалом ради сохранения основного.

А что для Маркета основное? Всё просто: дать пользователю возможность купить товар. Оформить заказ. Да, вокруг этого существует масса полезных и нужных вещей — рекомендации, фильтры, красивые картинки, точный расчёт доставки до минуты. Но если что-то идёт не так, мы должны уметь отбросить всё лишнее, но сохранить ядро. Кстати, это характерно для многих сложных систем: из полутора тысяч наших сервисов действительно критичных для оформления заказа (то, что мы называем «Mission critical») — всего около 50. Наша задача — выделить их, подготовить и уметь работать в режиме, когда доступны только они.

Как это выглядит на практике? Вот простой пример с корзиной. Пользователь добавил две упаковки геля для душа, а потом решил взять три и нажал на «плюсик». В этот момент запускается цепочка запросов к разным системам, вплоть до хранилища остатков на всех складах Маркета. Мы должны проверить, а есть ли третья упаковка в наличии. Наш внутренний SLA на ответ от системы стоков — не больше 50 миллисекунд. Фронтенд просто не будет ждать дольше.

И вот тут вступает в игру graceful degradation. Если система стоков не успела ответить за эти 50 мс (может, она перегружена или есть временные проблемы с сетью), мы не блокируем пользователя. Корзина и фронтенд позволяют ему добавить товар, оформить заказ и даже оплатить его. А уже потом, в асинхронном режиме, наша система снова обращается к системе стоков: «Слушай, мы тебя спрашивали, ты не ответила. А вот этот товар для этого заказа точно есть в нужном количестве?» Если да — отлично, заказ едет дальше. Если нет — мы связываемся с пользователем: «Извините, этого геля осталось только две штуки. Можем привезти две или отменить позицию?». Да, это не идеальный опыт, но заказ оформлен, и мы не потеряли клиента в критический момент. Мы платим потенциальной сложностью за надёжность основного сценария.

02 (6).png

Конечно, graceful degradation — это не единственный принцип. Есть и другие базовые паттерны, которые должны закладываться при разработке, и это ответственность каждого инженера в команде:

Deadline Propagation — умное управление ожиданиями. Когда сервис А делает запрос к сервису Б, он сразу сообщает: «Я готов ждать ответа N миллисекунд». Если сервис Б понимает, что не уложится, он может даже не начинать обработку, экономя свои ресурсы и не заставляя сервис А висеть в ожидании. Это помогает не перегружать систему лишними запросами, которые всё равно будут отброшены по таймауту.

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

Circuit Breaker — механизм самозащиты сервиса. Если система обнаруживает, что запросы к какому-то внешнему компоненту постоянно завершаются ошибкой или таймаутом, или если сам сервис не может справиться с нагрузкой, она может временно «разомкнуть цепь» — перестать отправлять запросы к проблемному компоненту или принимать новые входящие запросы на себя. Это даёт время «остыть», предотвращает лавинообразный отказ и позволяет системе восстановиться, прежде чем снова начать обрабатывать трафик.

Congestion Control — управление входящим потоком запросов для защиты системы от перегрузки. Когда количество обращений превышает возможности обработки, включаются механизмы, ограничивающие трафик: от простого rate limiting до динамической адаптации пропускной способности в зависимости от загрузки. Это позволяет сохранить стабильность, не допуская лавинообразного отказа из-за нехватки ресурсов.

Эти паттерны — фундамент, на котором должна строиться любая сложная и высоконагруженная система, претендующая на стабильность. И закладывать их нужно на этапе проектирования, а не пытаться прикрутить «сбоку», когда система уже начала падать под нагрузкой.

Управление надёжностью на практике

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

Интересно, что в сферу надёжности многие, и я в том числе, приходят из инфраструктуры. Это довольно логично. Когда ты отвечаешь за «железо», сети, системы авторизации — то есть за самый базовый слой, на котором всё остальное работает, — ты по умолчанию несёшь ответственность за стабильность. Никакой сервис не может быть надёжнее платформы под ним. Если у тебя база данных лежит по несколько часов в год, то сервис, который от неё зависит, никогда не достигнет целевых «четырёх девяток» доступности. Вот и приходится тебе постоянно договариваться о требованиях, окнах обслуживания, архитектуре систем, гарантиях и контрактах в интеграциях между системами. Так, незаметно для себя, ты из инженера инфраструктуры превращаешься в инженера по надёжности. Это определённый level-up, потому что тебе нужно разбираться не только в технике, но и в теории вероятностей, управлении проектами и процессами.

В мире есть устоявшаяся роль — SRE, Site Reliability Engineer. Это человек, который системно занимается инженерией надёжности. Однако в России в целом, и у нас в том числе, SRE в чистом виде встречается редко. Часто это либо бывшие системные администраторы, либо разработчики, сфокусированные на узком участке. Поэтому мы идём по пути, когда функции SRE частично распределяются. Да, у нас есть инженеры, глубоко погружённые в инфраструктуру и платформенные решения. Но мы также ожидаем, что и сами разработчики будут думать о надёжности, проектировать с учётом отказоустойчивости и использовать те самые паттерны, о которых я говорил ранее. Это общая ответственность.

03 (5).png

Что делать, когда инцидент всё-таки случается

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

Иногда для решения по-настоящему крупных и срочных проблем мы собираем «war room». Это не повседневная практика, а инструмент для коротких, интенсивных сессий во время серьёзных сбоев или пиковых нагрузок. Мы собираем в одной комнате или в одном голосовом чате ключевых инженеров — самых опытных, тех, кто досконально знает архитектуру, даже если они уже руководители и не дежурят. Оффлайн-коммуникация голосом в группе гораздо быстрее, чем переписка в чатах или зум-коллы. Можно мгновенно распределить задачи: «Ты делаешь это, ты смотришь сюда, ты следишь за этим графиком».

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

  • Координатор инцидента. Это «мозг» операции. Человек, который понимает общую картину, может быстро оценить гипотезы, отсечь лишнее, направить усилия команды и сказать: «Так, здесь закопались, пробуем вот это». Как правило, это самый опытный инженер с глубоким пониманием связности систем, прошедший через множество факапов. Его задача — не самому чинить, а дирижировать процессом.
  • Менеджер инцидента. Это «руки и голос» операции вовне. Человек, который ведёт статусы, вызывает нужных людей из других команд, общается со смежниками и руководством, снимая эту нагрузку с координатора и инженеров.

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

04 (5).png

Раньше для таких случаев писали многостраничные DRP (Disaster Recovery Plans) — детальные инструкции на все случаи жизни. Но в нашем динамичном мире, где проблемы часто уникальны, такие планы быстро устаревают. Поэтому мы фокусируемся на процессе и инструментах. У нас есть чёткое понимание, кто кого зовёт в случае проблем, кто за что отвечает. И этот процесс поддерживается автоматизацией: например, специальный бот при срабатывании определённого алерта может сам создать чат, позвать туда нужных дежурных и ответственных за компонент, запросить первичный статус и регулярно напоминать об обновлениях. Он же агрегирует информацию из всех активных инцидентных чатов в один общий канал для руководителей. Это позволяет всем быть в курсе происходящего, не дёргая инженеров, и быстро координировать усилия, не полагаясь на бумажные инструкции.

Инструменты и методы предотвращения сбоев

Реагировать на инциденты — это всегда борьба с последствиями. Гораздо эффективнее работать на опережение, выстраивая проактивную защиту и постоянно проверяя систему на прочность. У нас это устроено следующим образом:

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

Дальше начинается самое интересное — проверка. Как убедиться, что система выдержит расчётную нагрузку? Через нагрузочное тестирование. Это обязательная практика для любого кода, который выезжает в продакшн и взаимодействует с внешним миром. Мы тестируем даже отдельные коммиты перед выкаткой, чтобы убедиться, что они не влияют на производительность. Но самое показательное — это виртуальные заказы прямо на продакшене.

Что это такое? Это почти настоящий заказ, который проходит через многие системы, но не попадает в финансовую отчётность, аналитику и, конечно, не уезжает к реальному покупателю. Используя такие виртуальные заказы, а также эмулируя поведение пользователей, которые просто ищут товары, мы можем генерировать синтетическую нагрузку поверх реальной, органической.

Как это работает: мы выбираем время, когда система относительно свободна, например, ночью или поздно вечером, смотрим на текущую органическую нагрузку (допустим, 10 тысяч заказов в час) и «доливаем» синтетическую нагрузку до нашего целевого значения, например, до 150 тысяч заказов в час, если мы готовимся к такому пику. И смотрим, как система справляется, где появляются хрупкие места. Конечно, реальные заказы всегда в приоритете. Если что-то ломается во время таких прогонов, мы останавливаемся, фиксируем проблему и идём её чинить. Такие тестирования мы проводим регулярно, раз или два в неделю, плюс более масштабные прогрузки перед ожидаемыми пиками.

05 (2).png

Чтобы всем этим управлять, мы разработали собственную платформу для нагрузочных тестов. Изначально команды использовали разные опенсорсные инструменты вроде JMeter или Gatling, но это приводило к зоопарку решений. Мы взяли за основу общую яндексовую разработку — серверную часть, которая непосредственно генерирует нагрузку, — и написали свой control plane, обвязки и UI. Наша цель была — сделать инструмент с максимально низким порогом вхождения. Сейчас любая команда может за день-два разобраться, подготовить сценарии для своего сервиса и начать его тестировать. Платформа интегрирована с нашими системами мониторинга, умеет автоматически останавливать прогоны при срабатывании определённых алертов, присылает уведомления в мессенджер со ссылками на дашборды и даже имеет кнопку «всё плохо, остановите», если инженер видит проблемы.

Но даже при всей проактивной подготовке иногда нагрузка может превышать ожидания или может случиться непредвиденный сбой. На этот случай у нас есть специальные инструменты, например, RPS limiter. Это механизм, жёстко ограничивающий количество запросов в секунду, которое может принять сервис. Если к сервису, способному обработать 100 RPS, прилетает 500 RPS, лимитер просто отбросит лишние 400. Да, часть пользователей получит ошибку, им придётся попробовать ещё раз. Это плохой опыт, и мы теряем часть этих запросов. Но это позволяет спасти сам сервис от полного падения и продолжить обрабатывать хотя бы какую-то часть трафика. Это крайняя мера, но иногда она необходима.

DDoS-атака на 1 млн RPS

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

Некоторое время назад у нас был показательный случай. На Маркет пришла DDoS-атака мощностью около одного миллиона запросов в секунду. К счастью, у Яндекса есть собственная мощная система защиты от DDoS и роботов, которая так и называется — «Антиробот». Под её «зонтиком» живёт множество сервисов Яндекса, и Маркет в том числе. Чтобы защита работала, нужно правильно настроить перенаправление трафика на серверы «Антиробота», а они уже фильтруют вредоносные запросы и присылают нам «чистый» трафик.

В тот раз «Антиробот» отработал отлично и отбил подавляющую часть атаки — почти весь миллион RPS. Нам также повезло, что злоумышленники били по конкретным URL, которые были не самыми критичными для основного функционала.

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

  • Пересмотрели ресурсы. Мы проанализировали компоненты, пострадавшие от этого трафика, и увеличили выделенные им ресурсы, чтобы создать запас прочности на будущее.
  • Настроили RPS-лимитеры. Для этих уязвимых точек мы внедрили и настроили те самые RPS-лимитеры, о которых я говорил
  • Улучшили взаимодействие с защитой. Мы запустили несколько совместных проектов с командой «Антиробота», чтобы научить систему лучше распознавать и фильтровать именно такой — целевой вредоносный трафик

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

Культура надёжности: Почему это бесконечный марафон

Часто возникает соблазн думать, что надёжность — это что-то, что можно один раз настроить «с запасом», а потом расслабиться и заниматься другими делами. Но это глубокое заблуждение, особенно в таком динамичном бизнесе, как наш.

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

А теперь реальный мир e-commerce. Сегодня вы печатаете десять книг, а завтра к вам приходит бизнес и говорит: «Отлично! Нашёл клиентов в соседних домах, на следующей неделе печатаем тысячу! Купим ещё станков, пусть и похуже качеством, ты же справишься?». Вы справляетесь, кое-как поддерживая новые станки. А через неделю: «Супер! Издательство из соседней деревни заказывает десять тысяч книг в месяц! Завтра привезём фуру станков разных моделей, давай масштабируй решение!». И вот вы уже бегаете между десятками разных станков, старые техпроцессы не работают, системы нет, и вы тонете в хаосе.

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

И здесь кроются две типичные ошибки, которые часто совершаются из-за непонимания этой марафонской природы надёжности:

  1. Недооценка подготовки и процессов. Как я уже говорил, в критической ситуации ты спустишься на уровень своей подготовки. Если нет выстроенных процессов инцидент-менеджмента, нет регулярных учений, нет понимания, кто за что отвечает, то во время реального сбоя начнётся паника и хаос. Люди будут тратить драгоценное время не на решение проблемы, а на выяснение, кого позвать и что делать. Отсутствие культуры подготовки — прямой путь к увеличению времени простоя и финансовым потерям.

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

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

Синергия технологии, процессов и людей

Итак, как вы видите, обеспечение надёжности такого сложного и динамичного продукта, как Яндекс Маркет, — это далеко не тривиальная задача. Это не просто набор технических трюков или героическое тушение пожаров в момент сбоя. Это комплексная, непрерывная работа, которая затрагивает все уровни нашей инженерии.

06.png

Стабильность Маркета строится на нескольких китах:

  • Продуманная архитектура и философия. Принципы вроде graceful degradation и использование правильных паттернов, таких как congestion control, deadline propagation, idempotency и circuit breaker, закладывают фундамент устойчивости на уровне кода и взаимодействия систем. Мы фокусируемся на сохранении core-функционала, даже если приходится жертвовать второстепенными вещами.
  • Проактивные инженерные практики. Мы не ждём, пока система упадёт. Мы постоянно проверяем её на прочность через нагрузочное тестирование, регулярные прогоны на продакшене, тщательное планирование мощностей и прогнозирование нагрузки в сотрудничестве с бизнесом.
  • Выстроенные процессы и правильные инструменты. Чёткий, автоматизированный процесс управления инцидентами, динамическое распределение ролей во время сбоев, собственные платформы для тестирования и инструменты защиты вроде RPS-лимитеров и антиддос платформ позволяют нам действовать скоординированно и эффективно как в штатных, так и в нештатных ситуациях.
  • Культура ответственности и непрерывного развития. Надёжность — это забота не только выделенной команды, но и каждого разработчика. Это культура постоянного анализа рисков, работы на опережение, извлечения уроков из инцидентов и понимания, что работа над стабильностью никогда не заканчивается.

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

  • backend