Главная / Статьи

За пределами P95: измерение задержки, которую действительно испытывают ваши пользователи

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

Издатель: REACTAPP.TOP17 мин чтения3974 слов

Источники: Your P95 Latency Is Lying to You.

Клиент сообщает, что продукт работает медленно. Кто-то открывает панель управления задержками, и там всё зеленое: P95 в пределах нормы, уровень ошибок стабилен, загрузка CPU низкая, количество подключений к базе данных значительно меньше установленного лимита. Соблазнительный вывод заключается в том, что жалоба, должно быть, неверна, и именно этот инстинкт — доверие графикам больше, чем словам человека, который просто ждал, — является настоящей ошибкой.

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

Что говорит и чего не говорит P95

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

Сам процентиль не является проблемой. Проблема заключается в том, какие выводы делают команды после его анализа. Фраза «P95 в порядке» часто служит своего рода сертификатом невиновности, который прекращает дискуссию. При этом незаметно упускается основная идея: никто из пользователей вашего продукта не сталкивается напрямую с процентилем. Люди сталкиваются с ожиданием — они нажимают кнопку и задаются вопросом, было ли это действие зарегистрировано. Они видят страницу, которая, кажется, отрисована, но не реагирует. Они смотрят на индикатор загрузки, в то время как несколько сервисов, работающих на фоне, показывают совершенно нормальные показатели.

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

При каждом запросе работают три «часа»

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

  • Часы сервера. Приходит запрос к вашему сервису, идет ответ, таймер останавливается. Именно это показывают большинство панелей управления backend.
  • Часы зависимостей. В процессе обработки запроса тратится время на аутентификацию, ожидание подключения к базе данных, внутренние HTTP-запросы, неудачные попытки доступа к кэшу, повторные попытки, обработку очередей, проверку флагов функций, взаимодействие с API сторонних сервисов и все те компоненты, которые «обычно работают быстро».
  • Часы пользователя. Пользователь нажал кнопку, затем ждал, пока экран станет использоваемым. Именно этот промежуток времени важен для пользователя.

Команды обычно оптимизируют первый этап работы и затем описывают продукт как быстрый. На приведённой ниже диаграмме эти три аспекта показаны рядом: сервис сообщает о времени отклика в 180 мс, тогда как цепочка зависимостей включает попытку повторного запроса, занимающую 600 мс, и человек за клавиатурой всё ещё спрашивает, почему страница загружается.

SERVER CLOCK

request in  ------------------------------> response out
              "API P95: 180ms"

DEPENDENCY CLOCK
request in  ---> auth ---> db ---> service A ---> retry ---> service B ---> response out
                 40ms    70ms      120ms        600ms       90ms

HUMAN CLOCK
click  ----------------------------------------------------------------> usable screen
       "Why is this still loading?"

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

Эндпоинт — это дверь, а путь пользователя — здание

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

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

User Clicks "Open Dashboard"
        |
        v
+----------------------+
| Frontend Shell       |
+----------------------+
        |
        +------> GET /profile
        |
        +------> GET /permissions
        |
        +------> GET /accounts
        |
        +------> GET /offers
        |
        +------> GET /notifications
        |
        +------> GET /limits
        |
        v
Screen Finally Becomes Useful

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

Именно поэтому утверждение «наш API быстрый» является лишь началом расследования, а не ответом. Дальнейшие вопросы могут быть неприятными, но необходимыми: быстрый по сравнению с чем, для кого и с какой точки измерения? Внутри границ вашего сервиса или с момента нажатия пользователя на кнопку?

Оставшиеся пять процентов — это не ошибка округления

Название «P95» создаёт впечатление, что проблемная часть незначительна. Пять процентов кажутся приемлемой ценой для масштабной работы, такой, которую может поглотить спокойный комитет по оценке.

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

Даже такое описание слишком упрощённо, поскольку медленные запросы распределяются не равномерно среди пользователей:

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

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

Именно поэтому жалобы пользователей следует рассматривать как данные. Люди не сообщают о проблемах в процентах; они рассказывают свои истории: «Каждый раз после нажатия кнопки отправки программа зависает», «Страница открывается, но данные появляются с задержкой», «Мне приходится перезагружать страницу дважды», «Всё работает, но работает медленно». Ни одна из этих фраз не является расплывчатой. Каждая из них — это отчет о производительности, написанный простым языком, а общая проблема заключается в том, что его ошибочно интерпретируют с помощью неверных показателей и делают вывод, что всё в порядке.

Два сервиса, один показатель P95, совершенно разные риски

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

SERVICE A

Most Requests        120ms - 260ms
Slow Requests        300ms - 380ms
Disaster Requests    Rare

SERVICE B

Most Requests        40ms - 80ms
Slow Requests        300ms
Disaster Requests    8s - 12s

Оба сервиса могут показывать примерно одинаковые значения P95. Только у сервиса B есть «ловушка», которая полностью находится за пределами 95-го процентиля, так что этот показатель её не видит. Чтобы выявить эту разницу, необходимо посмотреть на значения P99, P99.9 и максимальное значение, или же на гистограмму/тепловую карту задержек.

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

Практическое правило: панель управления с перцентилями должна запускать диалог, а не прекращать его. Вопрос заключается не только в том, «каков наш P95?», но и в том, «какая проблема стоит за этим числом?»

Самые большие задержки возникают между командами

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

Самые сложные проблемы возникают из-за разногласий между командами. Бэкенд сообщает, что API работает нормально. Фронтенд указывает, что он ждет ответа от бэкенда. Платформа говорит, что шлюз в порядке. Команда по управлению базой данных утверждает, что база данных работает корректно. Отдел продукта сообщает, что пользователи по-прежнему недовольны. Каждая из этих команд говорит правду, и именно это делает ситуацию настолько раздражающей.

В таких случаях система не медлит в каком-то одном очевидном месте. Она медлит в «швах»:

  • при передаче данных между сервисами;
  • при повторных попытках, которые удваивают время выполнения запроса;
  • при втором запросе, который вообще не должен был быть отправлен;
  • во время проверки разрешений, которая выполняется после того, как уже началась дорогая обработка;
  • при неудачном доступе к кэшу, который остается незамеченным, поскольку выполнение запроса всё равно заканчивается до достижения порогового значения для сигнализации;
  • в сервисе стороннего поставщика, который все называют «внешней зависимостью», что звучит менее неловко, чем признание того, что он является частью пользовательского опыта;
  • в очереди, ещё до того, как начнётся выполнение вашего кода;
  • во время сериализации, после завершения обработки бизнес-логики;
  • на фронтенде, поскольку API возвращает данные, ориентированные на базу данных, а не на экран, и клиенту приходится их пересобирать.
  • P95 не ввел никого в заблуждение своей ложностью. Он ввёл в заблуждение тем, что существовал в одиночку. Изолированный показатель позволяет каждой команде демонстрировать свою невиновность, пока пользователь продолжает ждать.

    Время, проведённое в очереди, всё равно считается задержкой

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

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

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

    Называние каждого этапа запроса

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

    Приведённый ниже фрагмент представляет собой обработчик в Spring Boot на Java, но этот подход можно применить напрямую в Express, Fastify или NestJS. Для запроса GET /home запускается LatencyTrace, связанный с заголовком X-Request-Id запроса. Каждый значимый шаг — загрузка информации о пользователе, получение прав, вызов сервисов, связанных с аккаунтами и предложениями, а также формирование ответа — оборачивается в функцию trace.time(...) с описательной меткой. В блоке finally функция trace.logIfTotalCrosses(Duration.ofMillis(700)) выводит статистику только тогда, когда общее время обработки запроса превышает 700 мс; таким образом, лог не содержит записей при нормальной загрузке, а содержит подробную информацию при медленной. Конкретная реализация менее важна, чем привычка, которую она формирует.

    @GetMapping("/home")
    public HomeResponse home(@RequestHeader("X-Request-Id") String requestId) {
        LatencyTrace trace = LatencyTrace.start("GET /home", requestId);
    try {
            User user = trace.time("db.user", () ->
                userRepository.findActiveUser()
            );
            Permissions permissions = trace.time("auth.permissions", () ->
                permissionClient.fetch(user.id())
            );
            List<Account> accounts = trace.time("accounts.http", () ->
                accountClient.fetchAccounts(user.id())
            );
            List<Offer> offers = trace.time("offers.http", () ->
                offerClient.fetchEligibleOffers(user.id())
            );
            return trace.time("response.mapping", () ->
                HomeResponse.from(user, permissions, accounts, offers)
            );
        } finally {
            trace.logIfTotalCrosses(Duration.ofMillis(700));
        }
    }
    

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

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

    GET /home took 1180ms
    

    Эта информация точна, но практически бесполезна, поскольку она не говорит ничего о том, куда ушло 1 180 мс. Версия с отслеживанием каждого шага сразу даёт ответ на этот вопрос:

    GET /home took 1180ms
    
    db.user              42ms
    auth.permissions     81ms
    accounts.http        156ms
    offers.http          823ms
    response.mapping     28ms
    

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

    В кодбазе Node.js можно достичь того же эффекта с помощью функции performance.now() перед каждым вызовом, ожидающим выполнения, и структурированного логгера, или более систематично — с использованием спанов OpenTelemetry, которые сохраняют одинаковые названия этапов между разными сервисами, благодаря чему анализ остается корректным даже в случае, когда медленный этап находится в чужом сервисе. Для более подробного рассмотрения сочетания логов, метрик и трейсов см. создание наблюдаемых API для Node.js.

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

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

    Проблема не в том, что инженеры не могут проводить контролируемые тесты. Проблема в том, что такие тесты склонны устранять именно ту «хаотичность», которая вредит пользователям:

    • Бенчмарк тестирует один конечный пункт; реальные действия пользователя запускают множество таких процессов.
    • Бенчмарк выполняется с уже загруженными кэшами; пользователи появляются после развертываний, удалений данных и использования «холодных» версий кода.
    • Бенчмарк измеряет успешные ответы; пользователи сталкиваются с частичными сбоями, повторными попытками, истечением времени ожидания и недоступными экранами.
    • Бенчмарк исходит из предположения о стабильности зависимостей; в реальных условиях зависимости могут работать нормально до самого момента, когда это перестанет быть так.
    • Бенчмарк изолирует один сервис; то, с чем сталкиваются пользователи, представляет собой совокупность множества сервисов наряду с браузерами, сетями, очередями, API-контрактами и решениями команд, которые могут больше не взаимодействовать друг с другом.

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

    Быстрый код не гарантирует быстрого продукта

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

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

    Когда самой медленной зависимостью является решение

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

    • Фронтенд обращается к шести API, хотя был бы достаточен один агрегированный ответ.
  • Каждый экран снова обращается к службе разрешений вместо того, чтобы использовать уже полученный результат.
  • Попытки повторной загрузки выполняются синхронно внутри пути запроса, предназначенного для пользователя.
  • Виджет с предложениями блокирует отображение всего главного экрана.
  • События аналитики должны быть зафиксированы до того, как пользователю будет разрешено продолжить.
  • API возвращает объекты в формате базы данных, оставляя задачу интерпретации на фронтенде.
  • Служба нижнего уровня помечена как «критическая», потому что никто не захотел сказать, что её функции могут загрузиться позже.
  • Самой медленной частью системы зачастую является выбор продукта, который никогда не оценивался, пробелы в ответственности или встреча из прошлого, результатом которой стала постоянная задержка. Для многих из этих проблем существуют хорошо известные решения: использование бэкенда для фронтенда, объединяющего запросы, отложенная загрузка незначимых элементов интерфейса, перенос операций повторных попыток и аналитики вне критической цепочки обработки, а также форматирование ответов с учетом особенностей экрана. Однако каждое из этих решений требует наличия у кого-то полномочий на изменение принятых решений.

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

    Зеленые панели управления могут снизить любопытство команд

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

    Именно так команды теряют доверие — не из-за отсутствия данных, а из-за использования данных в качестве причины для игнорирования мнений пользователей. У пользователя нет вашей панели управления; у него есть ваш продукт. Если ему кажется, что продукт работает медленно, это уже доказательство. Это не полное или идеальное доказательство, но это доказательство.

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

    Начните с того, что пытался сделать пользователь

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

    • Для открытия панели управления измеряйте время до того момента, когда панель действительно готова к использованию.
    • Для отправки формы измеряйте время с момента отправки до появления подтверждения.
    • Для загрузки отчета измеряйте время с момента клика до того, как файл становится доступным.
  • Для оплаты измеряется расстояние от начального состояния до окончательного урегулированного состояния.
  • Это кажется очевидным, однако многие системы не оснащены инструментами в таком формате. Их измеряют по границам команд, потому что так проще настроить инструменты и получить структурированные панели управления. Отслеживание процессов выполнения задач сложнее, и результаты бывают менее удовлетворительными, но именно из этих менее удовлетворительных результатов возникают улучшения продукта. С клиентской стороны API браузера, такие как интерфейсы Performance и User Timing, позволяют явно отмечать моменты «клик пользователя» и «доступность экрана», а связывание этих отметок с идентификатором запроса позволяет привязать человеческое время к данным с сервера. Если медленная работа связана с отрисовкой, а не с сетью, статья о диагностике производительности React за пределами времени ответа API рассматривает эту сторону проблемы.

    Относитесь к показателям с осторожностью

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

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

    Основные выводы

    Опасная ситуация — это не метрика, которая явно неверна; её легко обнаружить. Это метрика, которая с такой уверенностью излагает частичную правду, что все перестают искать более полную картину. В следующий раз, когда кто-то скажет, что P95 в порядке, не спорьте с цифрой; спросите, что она не учитывает. Учитывалась ли время ожидания в очереди, попытки повтора, ожидание с фронтенда, вызов стороннего сервиса, действия пользователя, который нажимает снова, так как кажется, что ничего не происходит, а также момент, когда экран действительно становится пригодным для выполнения задачи, ради которой пришел клиент?

    • P95 превышает средние значения, но скрывает форму распределения, степень выраженности хвоста и тех, кто пострадал; используйте его вместе с более высокими процентилями, гистограммами и разбивкой по арендаторам или регионам.
    • Различайте часы сервера, зависимостей и людей, и убедитесь, что за каждыми из них кто-то отвечает.
    • Путь пользователя обычно включает множество вызовов; измеряйте весь путь, а не только конечные точки.
    • Таймеры приложений часто не учитывают ожидание в очереди, время подключения и задержки цикла событий; измеряйте эти показатели явно.
    • Отслеживание времени выполнения каждого этапа запроса и запись данных при превышении пороговых значений заменяют обвинения на доказательства.
    • Часть задержек является результатом решений, связанных с продуктом и ответственными лицами, и для их устранения необходимы полномочия на внесение изменений.
    • Рассматривайте жалобы пользователей как отчеты о производительности, а панели управления — как один из источников информации среди других.