В преддверии старта курса "Highload Architect" приглашаем всех желающих посетить открытый вебинар на тему "Паттерны горизонтального масштабирования хранилищ".


А пока делимся с вами традиционным переводом материала.


Пользователи Netflix продолжают смотреть любимые сериалы, пока инфраструктура самостоятельно восстанавливается после системного сбоя

Авторы: Мануэль Корреа (Manuel Correa)Артур Гонингберг (Arthur Gonigberg) и Даниэль Уэст (Daniel West)

Застрять в пробке — нет ничего хуже для любого водителя в мире. Движение замедляется до скорости черепахи, зачастую из-за какой-то ерунды или вообще без причины. Мы, инженеры из Netflix, постоянно ищем способы улучшения управления трафиком — в нашем случае сетевым, — но представим на минуту, что мы управляем уличным движением. Что если бы мы знали, насколько важно проехать тому или иному водителю, и могли бы выборочно обеспечивать движение отдельных машин, вместо того, чтобы заставлять ждать всех?

Сотрудники технических подразделений Netflix стремятся сделать так, чтобы сервис Netflix работал всегда, когда он вам нужен. И все же, еще совсем недавно (буквально в прошлом году) в наших системах регулярно возникали «пробки». У нас были автоматические выключатели, но не было прогрессивного способа ограничения нагрузки. Задавшись целью улучшить опыт наших подписчиков, мы внедрили прогрессивное ограничение нагрузки на основе приоритизации запросов.

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

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

  1. Согласованно определять приоритеты запросов для устройств разных типов (мобильные устройства, браузеры и телевизоры).

  2. Прогрессивно регулировать выполнение запросов с учетом приоритета.

  3. Оценивать предположения относительно приоритета запросов с применением хаос-инжиниринга (намеренного внесения сбоя).

Далее приведена итоговая архитектура, которую мы разработали: с регулировкой по приоритету и применением хаос-инжиниринга.

 

Общая архитектура воспроизведения с регулировкой по приоритету и хаос-инжинирингом

Построение таксономии запросов

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

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

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

  • CRITICAL. Этот трафик влияет на способность воспроизводить видео. Если запрос завершается неудачно, на экранах подписчиков отображается сообщение об ошибке.

По атрибутам запросов служба шлюза API (Zuul) относит запросы к категориям NON_CRITICAL, DEGRADED_EXPERIENCE и CRITICAL и вычисляет значение приоритета в диапазоне от 1 до 100 для каждого запроса с учетом его индивидуальных характеристик. Это вычисление выполняется в первую очередь, чтобы его результат был доступен в течение остальной части жизненного цикла запроса.

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

Определение лучшего места для регулировки трафика

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

Регулировка служб

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

Глобальная регулировка

Другой случай, когда проблемы испытывает уже сама система Zuul. В отличие от описанной выше ситуации, глобальная регулировка затрагивает все серверные службы, находящиеся позади Zuul, а не какую-то одну из них. Такое глобальное регулирование может стать причиной намного более значительных проблем для подписчиков. Ключевыми показателями, используемыми для запуска глобального регулирования, являются загрузка ЦП, количество одновременных запросов и количество подключений. При превышении любого порога для этих показателей система Zuul начинает агрессивно регулировать трафик, чтобы обеспечить свою работоспособность на время восстановления системы. Эта функция имеет важнейшее значение: если система Zuul выйдет из строя, трафик вообще не сможет проходить через наши серверные службы, что приведет к полной остановке работы сервиса.

Внедрение прогрессивного ограничения нагрузки на основе приоритетов

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

 

Приведенный выше график — это пример применения кубической функции. По мере роста процента перегрузки (то есть диапазона между порогом регулирования и максимальной емкостью) порог приоритета реагирует очень медленно: при 35 % он все еще составляет более 90 %. Если же работоспособность системы продолжает ухудшаться, то порог приоритета опускается до 50 при 80 %, а затем постепенно падает до 10 при 95 % и т. д.

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

Обработка лавины повторных попыток

Когда система Zuul принимает решение отбросить трафик, она отправляет устройствам сигнал, сообщающий, что им нужно сбавить обороты. Делает она это путем указания количества повторных попыток, которые они могут выполнить, а также промежутка времени, в течение которого они могут это делать. Например:

{ “maxRetries” : <max-retries>, “retryAfterSeconds”: <seconds> }

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

Проверка правильности классификации запросов

Чтобы проверить, правильно ли тот или иной запрос классифицирован в рамках нашей таксономии запросов (NON_CRITICAL, DEGRADED или CRITICAL), нам нужен был способ оценить уровень комфорта пользователя в момент, когда этот запрос отбрасывается. Для этого мы использовали наш внутренний инструмент внедрения сбоев (FIT) и создали точку внедрения сбоев в Zuul, с помощью которой мы могли отбросить любой запрос по указанному приоритету. Это дало нам возможность вручную имитировать ограничение нагрузки путем блокировки диапазонов приоритетов для определенного устройства или подписчика, чтобы получить представление о том, какие запросы можно спокойно отбрасывать, никак не затрагивая пользователя.

Постоянный пересмотр классификации запросов

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

Эта платформа позволяет нам проводить A-/B-тестирование, при котором небольшое количество действующих подписчиков на 45 минут добавляется в контрольную и экспериментальную группы, после чего для экспериментальной группы выполняется регулирование запросов с различными приоритетами в течение этого времени. Это позволяет нам отслеживать различные реальные ситуации и оценивать их влияние на то, как сервис воспроизводит видео для пользователей. Платформа ChAP анализирует показатели KPI для каждого устройства подписчиков и определяет, есть ли отклонения в показателях контрольной и экспериментальной групп.

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

Эксперименты для обнаружения регрессии до и после исправления ошибки (показатель SPS указывает доступность стриминга)

Пожинаем плоды

В 2019 году до внедрения прогрессивного ограничения нагрузки в работах служб стриминга Netflix возникали перебои, из-за которых значительное число подписчиков не могло смотреть видео в течение некоторого времени. В 2020 году, спустя считаные дни после развертывания решения, инженерная группа начала отмечать преимущества его внедрения. В системах Netflix возникала похожая проблема, потенциальным следствием которой мог стать такой же перебой в работе сервиса, как и в 2019 году. Однако система прогрессивного ограничения нагрузки Zuul включилась и стала ограничивать трафик, пока работоспособность сервиса не была восстановлена в полном объеме. При этом способность подписчиков просматривать видео не пострадала вовсе.

На приведенном ниже графике показан стабильный показатель доступности стриминга: число потоков в секунду (SPS), когда система Zuul выполняет прогрессивное ограничение нагрузки с учетом приоритета во время инцидента. Разными цветами на графике отмечены запросы с разными приоритетами, выполнение которых регулируется.

Подписчики спокойно смотрели свои любимые сериалы на Netflix, пока инфраструктура самостоятельно восстанавливалась после системного сбоя.

Это еще не все

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

Если вы заинтересованы помочь Netflix продолжать работать, несмотря на нестабильность систем и непредвиденные сбои, свяжитесь с нами.


Узнать подробнее о курсе "Highload Architect".

Записаться на открытый урок "Паттерны горизонтального масштабирования хранилищ".