Site icon AppTractor

Исправление снижения производительности до того, как оно произойдет

Netflix используют 222 миллиона человек, и он работает на более чем 1700 типах устройств, от самых современных смарт-телевизоров до недорогих мобильных устройств.

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

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

Что мы подразумеваем под производительностью?

Технически метрики «производительности» — это те, которые относятся к скорости отклика или задержке приложения, включая время запуска.

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

В Netflix термин «производительность» обычно включает в себя как показатели производительности (в строгом смысле), так и показатели потребления памяти, и именно так мы используем этот термин здесь.

Почему мы запускаем тесты производительности для коммитов?

Сложнее рассуждать о профилировании производительности pre-production кода, поскольку мы не можем собирать показатели в реальном времени для кода, который еще не выпущен. Мы тестируем canary версию перед отправкой, и она проверяется сотрудниками Netflix — для нее получается тот же набор показателей, что и для production версии. Несмотря на то, что canary релиз является полезным пробным прогоном для ожидающей отправки версии, он иногда пропускает регрессии, потому что канареечная пользовательская база составляет лишь часть production релиза. И в случае обнаружения регрессии в ней, все равно требуется сложный и трудоемкий откат или исправления.

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

Что такое тесты производительности?

Целью наших тестов производительности TVUI (TVUI Performance Tests) является сбор показателей потребления памяти и скорости отклика при моделировании всего спектра взаимодействий пользователей с Netflix TV.

Существует около 50 тестов производительности, каждый из которых предназначен для воспроизведения разных аспектов вовлеченности пользователей. Цель состоит в том, чтобы каждый тест был кратким и фокусировался на конкретной, изолированной части функциональности (запуск, переключение профилей, прокрутка списков, выбор эпизода, воспроизведение и т.д.), в то время как набор тестов в целом должен охватывать весь опыт пользователя с минимальным дублированием. Таким образом, мы можем запускать несколько тестов параллельно, а отсутствие длительных тестов позволяет управлять общим временем тестирования и повторять тестовые прогоны. Каждый тест выполняется на комбинации устройств (физических и виртуальных) и версий платформы (SDK). Каждую уникальную комбинацию теста/устройства/SDK мы будем называть вариантом теста.

Мы запускаем полный пакет производительности дважды за пул реквест (PR):

Измерение

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

Мы приняли следующие решения:

Какие проблемы?

Когда Netflix работает в производственной среде, мы собираем данные о производительности в режиме реального времени, что позволяет относительно легко делать выводы о производительности приложения. Гораздо сложнее оценить производительность пре-продакшн-кода (изменения смерджены с основной веткой, но еще не выпущены) и еще сложнее получить данные производительности для несмердженного кода в PR. Метрики тестов производительности уступают метрикам использования в реальном времени по нескольким причинам:

Первоначальный подход: статические пороги

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

Было несколько проблем с подходом статических порогов:

Пивот: обнаружение аномалий и точек изменения

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

Мы остановились на двояком подходе:

Обнаружение аномалий

Мы определяем аномалию как любую точку данных в метрике, которая более чем на n стандартных отклонений выше недавнего среднего значения, где недавнее среднее значение и стандартное отклонение получены из предыдущих m тестовых прогонов. Для тестов производительности Netflix TV мы в настоящее время установили n на 4 и m на 40, но эти значения можно настроить, чтобы максимизировать отношение сигнал/шум. При обнаружении аномалии тесту присваивается статус «сбой» и генерируется предупреждение.

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

Точки изменения

Точки изменения — это точки данных на границе двух различных шаблонов распределения данных. Мы используем метод под названием e-divisive для анализа 100 самых последних тестовых запусков, используя реализацию Python, основанную на этом примере.

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

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

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

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

Дополнительные настройки

Прогонов за тест

Чтобы устранить предвзятость в определении неудач, мы решили запускать все тесты 3 раза, независимо от результата. Мы выбрали 3 итерации, чтобы предоставить достаточно данных для устранения большей части шума устройства (тесты распределяются по устройствам случайным образом) без создания узкого места в производительности.

Суммирование итогов тестовых прогонов

Затем нам нужно было выбрать методологию для сжатия результатов каждой партии из 3 прогонов в одно значение. Цель состояла в том, чтобы игнорировать выбросы, вызванные неустойчивым поведением устройства.

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

Все точки данных (3 прогона за сборку)

Выбор медианного значения для сборки

Выбор минимального значения сборки

Каковы результаты?

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

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

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

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

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

Регрессивная сборка выше порога оповещения

Последующая сборка значительно ниже порога оповещения

c) Тесты производительности PR, которые почти всегда были красными (поскольку вероятность нарушения хотя бы одного статического порога всегда была высокой), теперь в основном зеленые. Когда тесты производительности окрашены в красный цвет, у нас гораздо больше уверенности в том, что имеет место регресс производительности.

d) Отображение количества аномалий и точек изменения для каждой сборки обеспечивает визуальное понимание того, какая сборка потенциально проблемная.

Что дальше?

Дальнейшая работа

Есть еще несколько вещей, которые мы хотели бы улучшить

Более широкое внедрение и новые варианты использования

На данный момент обнаружение аномалий и точек изменения применяется к каждому коммиту в репозитории TVUI и находится в процессе развертывания для коммитов в репозитории TV Player (уровень, управляющий операциями воспроизведения). Другие команды Netflix (за пределами телевизионной платформы) также проявили интерес к этим методам, и их конечной целью является стандартизация обнаружения регрессии в Netflix.

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

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

Итоги

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

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

Обсуждаемые здесь методы поиска аномалий и точек изменения можно использовать для выявления регрессий (или прогрессий), неожиданных значений или точек перегиба в любых хронологически упорядоченных количественных данных. Их полезность выходит далеко за рамки анализа производительности. Например, их можно использовать для определения точек перегиба в надежности системы, удовлетворенности клиентов, использовании продукта, объеме загрузок или доходах.

Мы рекомендуем вам попробовать эти методы на ваших собственных данных. Мы хотели бы узнать больше об их успехе (или иначе) в других контекстах!

Источник

Exit mobile version