Site icon AppTractor

Измерение производительности мобильных приложений в продакшене

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

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

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

Краткая история команды App Performance

В Booking.com мы уже давно следим за показателями производительности приложений. Например, первая метрика времени запуска для iOS была введена в 2016 году. Примерно в 2019 году была создана команда, отвечающая за мониторинг и улучшение производительности.

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

Занимаясь функциональными улучшениями в метриках, мы также решили полностью переписать библиотеки производительности, одновременно переходя от старых языков Objective-C/Java к современным Swift/Kotlin. На протяжении всего этого процесса мы проектировали наши библиотеки так, чтобы они были полностью независимы от других инфраструктур Booking, вводили внешние зависимости, такие как эксперименты, хранение и работа с сетью.

Почему бы не использовать существующие инструменты сторонних разработчиков

Нет недостатка в бесплатных и платных инструментах для мониторинга производительности приложений. Apple и Google предлагают некоторые готовые решения для мониторинга, есть и несколько крупных сторонних игроков, таких как Firebase Performance.

Однако к нашему инструменту мониторинга было три основных требования, все из которых были связаны с интеграцией в инфраструктуру Booking и учетом особенностей нашей культуры разработки:

К сожалению, ни одно стороннее решение не соответствовало даже двум из трех наших критериев. Поэтому нам пришлось разрабатывать собственное.

Что мы измеряем

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

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

Время запуска приложения

Метрика App Startup Time измеряет время в миллисекундах с момента нажатия пользователем иконки приложения на главном экране до того, как приложение отрисует свой первый кадр.

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

Более подробную информацию и официальные рекомендации по процессу запуска приложений для каждой платформы вы можете найти в официальной документации (iOS и Android).

Время до интерактивности

Время до интерактивности (TTI) — это время в миллисекундах, которое проходит с момента начала создания экрана до появления первого кадра содержательного контента. Для этого:

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

Изначально эта метрика была определена Google для веб-разработки, но мы обнаружили, что она очень полезна и отлично подходит и для мобильных приложений.

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

Кроме того, мы используем метрику Time To First Render для выявления деградации, вызванной созданием и рендерингом экрана (см. следующий раздел).

Время до первого рендера

Время до первого рендера (Time To First Render, TTFR) — это время в миллисекундах, которое проходит с момента начала создания экрана до момента рендеринга первого кадра.

Оно начинается в то же время, что и общее измерение TTI, но может остановиться раньше. В наиболее распространенном случае экран должен быть готов к отрисовке как можно скорее, но не обязательно сразу показывать значимое содержимое. Обычно экран может показывать некий «индикатор прогресса» и выполнять некоторые тяжелые инициализации в фоновом режиме. Мы прекращаем отслеживание TTFR, как только отрисовывается первый кадр, поэтому метрика довольно близка к измерению времени создания экрана. Это позволяет нам предотвратить зависание потока пользовательского интерфейса во время создания, что приводит к улучшению пользовательского опыта.

Эта метрика напрямую влияет на TTI и может также влиять на производительность рендеринга.

Производительность рендеринга

Чтобы взаимодействие пользователя с приложением было плавным, приложение должно рендерить кадры менее чем за 16 мс, чтобы достичь 60 кадров в секунду (примечание: на многих современных устройствах этот показатель может быть уменьшен из-за более высокой частоты кадров на экране, 90 или 120 кадров в секунду, но в этой статье мы будем говорить о 60 кадрах в секунду). Если время рендеринга кадра превышает 16 мс, то система вынуждена пропускать кадры, и пользователь будет ощущать это в приложении.

Давайте попробуем представить, как приложение рендерит кадры на временной шкале:

Есть 2 основных фактора, которые влияют на то, насколько плохой может быть производительность рендеринга:

Учитывая эти два фактора, мы можем вывести определение для метрики, которая довольно точно отражает производительность рендеринга:

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

Время замирания может быть одинаковым при различном поведении: 1 замораживание с 1000 мс, 100 замораживаний с 10 мс. Кроме того, время замирания может увеличиться без каких-либо дополнительных изменений, просто за счет увеличения продолжительности сессии (например, когда каждый элемент прокручиваемого списка генерирует несколько медленных кадров и пользователь начинает прокручивать его больше, это приводит к увеличению общего времени замирания).

Для выявления таких ситуаций мы также используем две дополнительные метрики:

Обоснование выбора метрики “Время замирания”

И Google, и Apple предлагают метрики для оценки производительности рендеринга. Изначально для мониторинга производительности рендеринга мы использовали метод, реализованный в Firebase, который предусматривал отслеживание медленных кадров (>16 мс для рендеринга) и замороженных кадров (>700 мс). Однако мы обнаружили, что эти метрики неадекватно отражают деградацию производительности рендеринга.

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

Более того, существует несоответствие в отражении изменений производительности. Время рендеринга представления, увеличившееся с 15 до 20 мс, регистрируется как такое же изменение метрики, как и увеличение с 15 до 300 мс, что не совсем точно отражает серьезность замедления.

Метрика Apple «Частота зависаний», которая рассчитывается как секунды времени зависания в час, оказалась более соответствующей тому, что нам было нужно. Она похожа на нашу метрику Freeze Time, но нормализуется путем деления общего времени зависания на продолжительность сеанса. Однако такая нормализация привела к тому, что метрика стала слишком чувствительной к изменениям в поведении пользователей.

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

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

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

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

Покажите мне код!

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

Эти легковесные библиотеки помогают собирать вышеупомянутые показатели и отправлять их в любую систему аналитики. Мы активно работаем над дальнейшими улучшениями и новыми функциями (например, мониторингом закрытий), однако она уже используется в основном приложении Booking на обеих платформах. Библиотека для iOS также используется в нашем приложении Pulse для владельцев недвижимости и в приложении Agoda от нашей родственной компании.

Не стесняйтесь пробовать, оставлять отзывы, а еще лучше — вносите свой вклад!

Авторы: Вадим Чеповский и Глеб Тарасов

Exit mobile version