Gray failure, то есть серый, или частичный, отказ — довольно коварная ситуация, когда система демонстрирует квазирабочее состояние. По проверкам состояния мы наблюдаем работоспособность ресурса, но когда отправляем на него реальную нагрузку — ничего не работает. Выглядит примерно так:

Инциденты прошлого года показали нам, что серые отказы в Yandex Cloud могут приводить к деградации доступности для пользователей. Мы регулярно выявляем системные причины и внедряем улучшения на уровне всей облачной платформы, о чём подробнее уже рассказывали в одной из недавних статей. Но иногда решение проблемы серых отказов может требовать действий на клиентской стороне, которые не всегда очевидны.
Меня зовут Александр Душеин, я технический лидер команды архитекторов Yandex Cloud и занимаюсь направлением клиентской надёжности. В этой статье я расскажу подробнее, что поможет избегать нештатных ситуаций:
какая работа по предотвращению серых отказов была проделана на нашей стороне за счёт слаженной работы команды;
какие настройки стоит взять на вооружение пользователям Yandex Cloud и какие рекомендации могут быть полезны всем ответственным за Disaster Recovery;
какие инструменты помогают проводить учения по отказоустойчивости инфраструктуры, чтобы выявлять неоптимально настроенные ресурсы.
Как возникают серые отказы и чем поможет инструмент Zonal Shift
После болезненных инцидентов прошлого года мы провели исследование того, как серые отказы в облачной инфраструктуре влияют на сервисы, размещённые в облаке. Обнаружилось, что у существенного количества наших заказчиков период даунтайма их сервисов совпадает с периодом серого отказа в облаке. Это означает, что инфраструктура таких пользователей не была готова к серому отказу, несмотря на то, что формально она зачастую соответствовала всем рекомендациям по отказоустойчивости.
Какой мы сделали вывод? Развитие отказоустойчивости в облаке должно двигаться в двух направлениях:
повышение отказоустойчивости облачной платформы (и с этой точки зрения мы регулярно рассказываем о внедрённых улучшениях, в том числе на Хабре);
синхронизация наших усилий с заказчиками, без чего тяжело достигнуть нужного результата.
Так внутри команды Yandex Cloud и появился трек клиентской надёжности, который объединил усилия разработчиков, архитекторов и менеджеров облака. Основными направлениями этого трека стали разработка инструментов повышения отказоустойчивости и повышение осведомлённости заказчиков. В рамках второго направления важно напомнить, как работает вся большая облачная платформа.
В прошлой статье мы рассказывали, как устроена сетевая связность: и внутри зоны доступности, и между зонами доступности. В контексте частичных отказов важно ещё раз вспомнить, что такое зоны и регионы.
Инфраструктура облака разделена на регионы и зоны доступности.
Зона доступности — это физически и логически изолированная часть инфраструктуры. Физическая изоляция значит независимость энергоснабжения, инженерных систем и сетевых подключений. Логическая независимость означает способность зоны обеспечивать работоспособность нагрузки при отказе иных зон.
Регион объединяет несколько зон доступности. Внутри региона обеспечивается прямая сетевая связность между зонами доступности, общее ресурсное пространство и общие API.
Например, регион ru‑central1 включает зоны доступности ru‑central1-a, ru‑central1-b и ru‑central1-d.

Ключевым сервисом, который даёт возможность строить высокодоступные сервисы, устойчивые к частичной или полной недоступности зоны, является балансировщик нагрузки.
Как работают балансировщики нагрузки
Балансировщики в общем случае состоят из двух основных частей:
Обработчика — элемента, принимающего трафик и распределяющего его между целевыми ресурсами;
Целевых ресурсов — группы ресурсов, принимающих трафик от обработчика.
В основе сценариев отказоустойчивости лежит автоматика, которая отслеживает состояние целевых ресурсов и перенаправляет запросы пользователей от обработчика только в те целевые ресурсы, которые готовы эти запросы обработать. В свою очередь, готовность целевого ресурса принимать запросы определяется с помощью механизма Health Check. И основная трудность настройки заключается в подборе релевантных значений проверок и корректной реализации проверок готовности на стороне целевого ресурса.
Автоматика проверок доступности может не срабатывать в случае частичных отказов в зоне доступности. Для восстановления работоспособности сервиса при таких отказах нужен механизм ручного перераспределения нагрузки из отказавшей зоны в исправные. Чтобы понять, как именно работает такой механизм, также важно учесть, что в Yandex Cloud балансировщики работают на нескольких уровнях:
Сетевой балансировщик нагрузки (Network Load Balancer, NLB) как основное средство для построения отказоустойчивых решений. Network Load Balancer распределяет TCP‑соединения между целевыми ресурсами. Он может быть внешним для обработки трафика из интернета (обработчик с публичным IP‑адресом) и внутренним (обработчик с приватным IP‑адресом) для обработки внутреннего сетевого трафика.
Балансировщик нагрузки уровня приложения (Application Load Balancer, ALB или L7-балансировщик) как более интеллектуальный, но вместе с тем и более затратный инструмент балансировки. Сервис архитектурно представляет собой сетевой балансировщик нагрузки Network Load Balancer, который распределяет сетевой трафик между ресурсными единицами — внутренними виртуальными машинами. Они выполняют функции обратных прокси, которые, в свою очередь, распределяют трафик далее между целевыми ресурсами заказчика. Application Load Balancer может распределять трафик на произвольные приватные IP‑адреса, например, на IP‑адреса за пределами облачной сети, на IP‑адреса обработчиков Network Load Balancer и другие.
Как устроены отказы на разных уровнях
Посмотрим по отдельности на разные варианты отказов по уровням.
Что может пойти не так на уровне сети. Один из вариантов серого отказа, который может произойти, — сбой в сетевой связности, когда по каким‑то направлениям связность работает, а по каким‑то нет. Например, могут сбоить каналы интернет‑провайдеров или внешние каналы конкретной зоны доступности.
В этом случае целевые ресурсы бэкенда в затронутой инцидентом зоне доступности могут по‑прежнему отвечать на все проверки Health Check и отдавать зелёный статус, но при этом не обрабатывать весь трафик или обрабатывать его некорректно. Эта ситуация может нарушить работу, поскольку сетевой балансировщик, распределяющий нагрузку по бэкендам, по‑прежнему будет рассчитывать на неработающий бэкенд со статусом «Всё ОК!»:

Что может пойти не так на уровне приложения. В случае ALB, балансировщика на уровне приложения (L7), ситуация с серыми отказами может немного амплифицироваться. Частичная деградация связности в зоне может привести к дополнительному ухудшению кросс‑зональных походов: трафик из «больной» зоны может литься в «здоровую» и наоборот.

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

Благодаря тому, что функциональность Zonal Shift поддержана и на уровне L7, в более сложной схеме также можно избежать каскадного сбоя из‑за амплификации. Мы можем явно выключать балансировку на бэкенды в зоне доступности, и семантически это работает аналогично NLB:

При этом важно помнить, что Zonal Shift закрывает балансировку трафика в зону, но не саму зону — то есть не исключает горизонтальную обработку трафика между сервисами. Например, если у клиента есть Kubernetes, растянутый на несколько зон доступности, то микросервисы также будут размещены в нескольких зонах и будут общаться между собой горизонтально.
А значит, на случай частичных отказов важно предусмотреть сценарий перераспределения трафика для своей архитектуры.
Что важно учесть с точки зрения настроек балансировки
Балансировщики призваны помочь клиентам сделать их сервисы более надёжными. Однако при изучении графиков и журналов по следам инцидентов, мы заметили, что нередко настройки балансировки бывают не оптимальны, что приводит к сбоям в работе сервисов.
Важные правила на уровне NLB
Делать проверки готовности целевых ресурсов достаточно часто, с интервалом не более 3 секунд.
Важно указать корректный порог работоспособности и порог неработоспособности — количество успешных или соответственно проваленных проверок состояния. Значения порога должны быть строго больше одной проверки.
Так, в нашем примере настройки отказоустойчивого сайта с сетевой балансировкой нагрузки мы рекомендуем делать по пять таких проверок.Чтобы проверки не приводили к повышенной нагрузке, на целевых ресурсах, реализация проверок не должна требовать много ресурсов для генерации ответа.
Пример плохой практики: использовать в качестве проверки запрос корневой страницы сайта.
Пример хорошей практики: отдельный URI для проверки состояния подключений к необходимым ресурсам (например, базам данных) и общей работоспособности.
Чек‑лист для сервисов, использующих ALB. Соблюдение этих рекомендаций поможет избежать проблем на стороне клиента.
По возможности размещайте балансировщики и бэкенд во всех зонах доступности. К сожалению, мы неоднократно сталкивались с ситуациями, когда балансировщик для сервиса был развёрнут только в одной зоне.
-
Указывайте зону доступности для целевых ресурсов.
При настройке
target group
и выборе целевых ресурсов указывайте информацию о зоне. Для этого есть два способа:Указать
subnet-id
— идентификатор подсети, в которой находится целевой ресурс.Использовать сервис Instance Groups для формирования ALB Target group. Такая интеграция позволит автоматически определить зону доступности на основе информации об инстансах ВМ.
Приоритет балансировки в зоне не сможет работать, если балансировка идёт в целевые ресурсы ALB без указания зоны доступности или в endpoint другого балансировщика (ALB или NLB) по имени сервиса.
-
Настройте проверки состояния (HealthCheck) для бэкендов и бэкенд‑групп следующим образом:
Проверки смотрят на само приложение, по возможности не используется отдельный порт. Для ALB Ingress и MK8S‑кластера следует настроить проверки состояния либо через аннотации
ingress.alb.yc.io/health-checks
, либо через CRD HttpBackendGroup.Интервал проверок до 3 секунд.
Число healthy/unhealthy‑порогов строго больше одной проверки.
Почему так:
При длинном интервале время реакции на проваленные проверки возрастает и накладывается мультипликатор
unhealthy_threshold
. Если выставить интервал в 5 секунд приunhealthy_threshold = 3
, то балансировщик определит, что запросы в target нужно слать только через 10–15 секунд.Если пороги
unhealthy_threshold
иhealthy_threshold
очень низкие, то балансировщик получит не тот статус здоровья, что на самом деле. Target может краснеть и зеленеть, мигая, как новогодняя ёлка.Самый ненадёжный случай настройки проверок состояния — когда проверки есть, но порт не тот. И отвечает на HealthCheck не само приложение, а например kubeproxy. Так бывает, если взять ALB Ingress и использовать его проверки по умолчанию.
Ещё важно, чтобы обработчик проверок состояния не тратил много ресурсов для ответа на бэкенде. Мы не можем проверить это на стороне ALB, это задача самого сервиса. Иначе проверки состояния могут нагружать бэкенд.
-
Для бэкенд‑групп и бэкендов в них укажите
locality_aware_routing_percent
со значением 100%.Это включит механизм приоритетной балансировки в зоне доступности, при этом даст возможность балансировать запросы в другие зоны. При проблемах трафик распределится по остальным целевым ресурсам в других зонах с учётом их состояния здоровья.
Это решение позволяет бороться с серыми отказами сети в зоне доступности: так запросы из здоровых зон не будут проходить в пострадавшую. Однако инстанс балансировщика сможет отправить запрос в доступные целевые ресурсы из других зон. Не происходит полной герметизации зоны на выход, но резко ограничиваются кросс‑зональные запросы на вход. Балансировка начинает меньше зависеть от точности определения здоровья у целевых ресурсов, что важно при серых отказах.
-
Не используйте механизм ретраев в балансировке.
Корректно и безопасно настроить ретраи, не получив retry storm и перегрузку системы в критической ситуации — задача не из простых. Поэтому мы рекомендуем полностью отказаться от ретраев на уровне балансировщика.
-
Заложите резерв ресурсов, чтобы выдержать перетекание нагрузки из проблемной зоны.
При размещении compute‑ресурсов для бэкенда рекомендуем явно заложить запас, достаточный, чтобы выдержать общую нагрузку на сервис силами бэкендов в двух зонах доступности из трёх. Важно, что в случае проблем при перераспределении трафика из одной зоны повышенная нагрузка на оставшиеся зоны не приведёт к перегрузке бэкенда.
Заключительные рекомендации для пользователей
В заключение хочу сказать вещь, возможно даже более важную, чем все приведённые выше рекомендации: пока отказоустойчивая конфигурация не протестирована, её нельзя считать отказоустойчивой. Можно потратить массу средств и ресурсов на резервирование, которое не спасёт в критический момент из‑за какой‑нибудь нелепой ошибки или недосмотра.
Проверьте свою конфигурацию: отключите с помощью Zonal Shift трафик в одну из зон доступности и убедитесь, что ваша инфраструктура действительно может это пережить без потерь.
В этом помогут наши подробные инструкции: