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

Меня зовут Костя Крамлих, я отвечаю за сетевую виртуализацию и сетевые сервисы в Yandex Cloud. К написанию этой статьи меня подтолкнула наша работа по предотвращению крупных инцидентов, наподобие тех, что произошли в конце 2024 года. Разрешить их удалось благодаря слаженной работе всей команды, и по итогам мы сделали выводы, которые не ограничиваются только устранением сетевых аварий.

Сегодня по материалам реальных событий расскажу о сетевой части:

  • что важно знать о том, как ломаются большие системы, на наших примерах;

  • как мы проанализировали все наши инциденты за последний год и что сделали, чтобы предотвратить появление проблем на инфраструктуре;

  • как подошли к внедрению этих улучшений небольшими шагами, чтобы они не стали источником новых инцидентов.

Что важно знать про сетевую виртуализацию в контексте отказоустойчивости  

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

  1. Изоляция сетей. Важнейшее свойство системы — сети должны быть гарантированно немаршрутизируемы между собой.

  2. Внедрение без даунтайма. Изменения в сети должны вводиться максимально аккуратно, с сохранением обратной совместимости, иначе клиентские сценарии могут пострадать.

  3. Предоставление широкой функциональности. Компании уже привыкли работать со своими сетями и хотят с минимальными усилиями делать что‑то похожее у себя в облаке. Например, нужны гибкие инструменты внешней связности: Cloud Interconnect для связи облака и on‑premise‑инфраструктуры, Managed NAT для доступа в интернет, Private Endpoint для IP‑связности до сервисов облака из непубличной сети.

При этом в построении виртуальной сети мы используем традиционную для сетей модель разделения на слои:

  • Config Plane — это то, что пользователь конфигурирует через API, и тем самым задаёт целевое состояние системы.

  • Data Plane — слой, который непосредственно обрабатывает пакеты пользователя. Он состоит из виртуальных роутеров (VRouter) на серверах и т. н. Cloud Gateways — виртуальных маршрутизаторов, которые далее выпускают трафик наружу через Cloud Border — группировку физических маршрутизаторов на точках присутствия.

  • Control Plane — управляющий слой, который доводит состояние Data Plane до того, что было описано пользователем в Config Plane. Здесь работают SDN‑контроллеры (Controllers) — это «мозг» виртуальных сетей. Задача контроллера — держать в голове правила доставки трафика до всех виртуальных машин (другими словами — маршрутные карты), и распространять эту информацию по всем виртуальным роутерам. Эти роутеры в свою очередь знают про принадлежность конкретной ВМ конкретной сети.

Во многом похожие схемы могут возникать в совершенно других инфраструктурах, например, при управлении семафорами на железнодорожном транспорте. Есть централизованные зоны управления, которые контролируют конкретные перегоны. Конкретный перегон — это такой Data Plane, аналог того, как у нас проходит трафик в виртуальных сетях. А централизованный «мозг» (аналог Control Plane) управляет всей системой так, чтобы это было эффективно для прохождения поездов.

Схематично всё описанное можно представить вот так:

Контроллеров в большой системе много, все они синхронизируются друг с другом с помощью протокола BGP
Контроллеров в большой системе много, все они синхронизируются друг с другом с помощью протокола BGP

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

  • Задача контроллеров — распределить маршрутные карты сетей по компонентам. В цифрах на наших больших объёмах это сотни инстансов Cloud Gateway, десятки тысяч виртуальных роутеров и сотни тысяч маршрутных карт в каждой зоне.

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

  • Любые изменения маршрутной информации в одной из зон доступности мы должны распространять и в другие зоны. Эту задачу решают контроллеры с помощью распределённого регионального сервиса (3AZ).

  • Виртуальная сеть обеспечивает изоляцию между клиентами — её нарушение приводит к существенным рискам. Если что‑то пойдёт не так и Data Plane не получит актуальные маршруты, безопаснее всего будет отозвать маршруты и снять трафик.

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

Как мы увидим — примеры таких сетевых инцидентов обычно демонстрируют паттерны, которые встречаются не только в сети.

Что именно может пойти не так

Частичный или полный отказ контроллеров. Опытные разработчики инфраструктуры наверняка не раз слышали про такой термин, как «скоррелированный отказ». Им описывают две ситуации:

  • все компоненты отказывают разом, например, из‑за одновременного проявления одного и того же бага (например, «запрос смерти»);

  • частичный или полный отказ одного компонента приводит к повышенной нагрузке на другие элементы, и они тоже выходят из строя.

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

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

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

Циклическая амплификация нагрузки. Система притормаживает, что приводит к тайм‑аутам у клиентов и повторам запросов, которые нагружают систему ещё сильнее. Возникает эффект снежного кома: система обрабатывает всё меньше запросов, клиенты делают всё больше ретраев, и так по кругу.

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

К сожалению, такое у нас тоже случалось, что привело к одному из крупнейших отказов в облаке на региональном уровне (одновременный отказ более одной зоны). Из‑за бага в системе контроллеры в одной зоне сгенерировали поток маршрутов примерно на 2M RPS, чем перегрузили Cloud Gateways до состояния каскадного скоррелированного отказа по OOM.

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

Как мы повышали устойчивость, чтобы не выстрелить себе в ногу

Опытный читатель к этому моменту наверняка уже почувствовал слона в комнате:

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

  • Любые изменения всегда с определённой вероятностью приводят к отказу.

Согласно DORA report даже у лучших команд change failure rate составляет от 5 до 15%. Это процент выведенных в продакшн изменений, требующих исправления.

Мы не могли просто навалиться всей командой и сделать 100 правок надёжности. Просто из‑за статистики: каждая десятая правка содержит баги, а каждая сотая — генерирует инцидент.

Нам требовалось небольшое число безопасных и обобщаемых улучшений. Все необходимые изменения мы приоритизировали следующим образом:

  1. Мы выписали все критичные инциденты 2024 года и набор планируемых изменений в одну таблицу.

  2. Оценили, насколько улучшения изменили бы ситуацию, если были бы внедрены до инцидента.

  3. Оценили трудоёмкость реализации и вероятность, что что‑то пойдёт не так при внедрении.

Примерно так:

Для каждого улучшения мы оценили пользу по формуле score=impact / (cost * risk_probability) и поранжировали по этому критерию все улучшения.

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

Это помогло нам найти и внедрить набор комплексных улучшений.

Например, ограничения на размер очередей в сервисе Compute помогли срезать существенную часть холостой работы и, по нашим оценкам, суммарно на 2–3 часа быстрее подняться после мартовского инцидента с питанием.

В процессе приоритизации мы сгруппировали решения в рамках направлений, сформулировали три ключевых направления работ и построили эффективный и при этом аккуратный план:

  • Топ-1: полная поддержка headless режима (aka fail‑safe) — сохранение работоспособности Data Plane даже при полном отказе Control Plane с гарантиями сохранения изоляции.

  • Топ-2: усиление модели зональности/региональности — в случае частичного или полного отказа зоны мы сохраняем работоспособность региона.

  • Топ-3: масштабирование в рамках зоны — сохранение устойчивости зоны по мере роста её масштаба.

В дополнение к мерам предотвращения инцидентов, мы вложились и в инструменты митигации, которыми также могли бы воспользоваться клиенты. Так, для NLB и ALB мы разработали инструмент для управляемого закрытия зоны на балансировщике — Zonal Shift, о котором коллеги расскажут подробнее в следующий раз.

Остановлюсь на каждом пункте чуть подробнее, что именно мы сделали по сетевой части.

Обеспечили headless, или fail-safe

Fail‑safe — это такой способ проектирования системы, в котором при возникновении сбоя система переходит в безопасное состояние, предотвращая нежелательные последствия, даже если это значит частичный отказ функциональности.

Этот подход касается не только IT, но и сложных систем вообще.

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

Вспомним нашу схему. Для прохождения трафика в узлах Data Plane требуется конфигурационная и маршрутная информация, получаемая из контроллеров. Без режима fail‑safe при отказе контроллеров в системе происходит автоматический отзыв маршрутов для сохранения консистентности и изоляции, как мы говорили в начале.

Чтобы реализовать fail‑safe‑режим, важно справиться с главным вызовом при отказе Control Plane: в этом режиме мы должны максимально долго прожить с имеющимся кешем, а чтобы закешированное состояние не устарело, нужно минимизировать изменения в системе. Маршруты могут устареть на фоне переезда виртуальных машин, изменения конфигурации балансировщиков. Нам же нужно было соблюсти баланс: обеспечить и изоляцию, и безопасность, и чтобы трафик шёл.

Для реализации этого мы сделали несколько изменений:

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

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

Новую схему протестировали на препроде. В результате тестов убедились: сейчас мы выдерживаем до 8 часов отказа Control Plane в отдельной зоне, без импакта на Data Plane‑нагрузки.

Снизили взаимное влияние зон в регионе

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

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

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

Сейчас это уже внедрено для NLB‑трафика и готов план для внедрения по другим классам трафика.

Позаботились о масштабировании

Крупный инцидент в «чёрную пятницу», который я упоминал, был связан с тем, что при большом потоке маршрутов (свыше 10k RPS) узлы виртуальных маршрутизаторов в управляющем контуре перегружались по памяти.

Для решения мы переработали устройство gobgp — опенсорсной имплементации BGP‑протокола. Результат до и после:

Нашу доработку мы уже залили в апстрим и сейчас договариваемся с опенсорс‑сообществом о внедрении.

Last, but not least

Для внедрения изменений, направленных на стабилизацию Сontrol Plane, нам также потребовалось вносить изменения в Data Plane на физических серверах. Исторически такие обновления были долгими, медленными и болезненными, так как приводили к кратковременной недоступности виртуальной сети на серверах. Здесь помог Blue Green Deployment, или side‑by‑side — это стратегия, которая минимизирует даунтайм и позволяет мгновенно обновлять приложение, не отклоняя ни одного запроса, за счёт реплики‑близнеца. При реализации этой стратегии мы выкатываем реплику, готовим её к работе и «прогреваем», а затем плавно переключаем на неё нагрузку. Если в ходе этого что‑то идёт не так, то откатываемся, иначе — тушим старую версию.


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

  • мы увидели, как устроена сетевая виртуализация, и с какими особенностями мы встречаемся в облаке, когда реализуем определённую архитектуру;

  • посмотрели, что в реализованной схеме может пойти не так на уровне контроллеров, и к каким инцидентам это приводит на больших масштабах;

  • разобрались, почему в такой крупной системе любые улучшения в сторону большей надёжности важно внедрять аккуратно;

  • прошлись по списку улучшений в нашей сетевой подсистеме за последний год — что уже внедрили и почему именно в таком порядке.

Помимо этого были и другие изменения на следующих слоях системы, которые уже выходят за рамки сетевой темы. Поэтому об изменениях в других частях инфраструктурных сервисов мы расскажем в следующий раз. А комплексный рассказ о том, как именно мы пересмотрели подходы к надежности я расскажу в докладе «Когда облако дало сбой: реальный кейс борьбы за отказоустойчивость» на HighLoad++ 6 и 7 ноября в Москве. Приходите, будет интересно.

Комментарии (0)