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

Сначала определите, какой запрос медленный.

Фраза «API тормозит» слишком широка для исправления. Уточните endpoint, сценарий пользователя, объём данных и момент появления проблемы: всегда, на пике нагрузки или после изменения. Отдельно посмотрите ошибки и таймауты — они могут указывать на иную причину, чем высокая задержка.

  • Фиксируйте не только среднее, но и распределение задержек: например, p50, p95 и p99 для важного endpoint.
  • Сравнивайте одинаковые условия: запрос, размер ответа, период нагрузки и версию приложения.
  • Заранее задайте цель: какой сценарий должен улучшиться и какой компромисс допустим.

Первый артефакт

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

Разложите время запроса на части.

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

01 /

Измерьте снаружи

Зафиксируйте задержку и ошибки глазами клиента или на входе в сервис.

02 /

Сопоставьте внутри

Свяжите медленные запросы с трассами, логами и показателями ресурсов за тот же период.

03 /

Выделите участок

Посмотрите, сколько времени уходит на SQL, внешние вызовы, ожидание, CPU и формирование ответа.

04 /

Проверьте под нагрузкой

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

Практический шаблон

Карта диагностики одного запроса

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

Сценарий

Endpoint, действие пользователя, размер ответа и характерная нагрузка.

Исходные показатели

Распределение времени ответа, частота ошибок и момент появления задержки.

Вклад участков

Отдельно оцените SQL, внешние вызовы, ожидание и обработку в приложении.

Проверка изменения

Повторите сценарий на сопоставимой нагрузке; сравните время, ошибки, ресурсы и корректность.

Ищите причину по признакам.

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

01 / ВАРИАНТ

База данных

Много повторных запросов, тяжёлый план или ожидание блокировок. Проверьте число SQL-вызовов на один запрос к API, журнал медленных запросов и план через EXPLAIN ANALYZE; в PostgreSQL удобна статистика pg_stat_statements.

02 / ВАРИАНТ

Внешний сервис

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

03 / ВАРИАНТ

Приложение и среда

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

Иногда причины складываются: медленный SQL увеличивает время занятости соединения, а затем появляются очереди и таймауты. Тогда требуется устранить первичный источник и снова измерить систему.

Причины, которые легко пропустить

  • Очередь PHP-FPM. Когда все воркеры (pm.max_children) заняты, новые запросы ждут свободного. В логах каждый запрос быстрый, а клиент видит задержку. Проверьте страницу статуса пула (pm.status_path) и счётчик listen queue.
  • Пул соединений с базой. Ожидание свободного соединения в метриках приложения выглядит как медленный SQL, хотя сам запрос в базе выполняется быстро.
  • Хвостовые задержки. Холодный кэш после выкладки, паузы сборщика мусора, редкие тяжёлые запросы и большие ответы без сжатия заметны в p99, но почти не видны в среднем времени.

Меняйте одну гипотезу и проверяйте эффект.

После диагностики сформулируйте проверяемое изменение: новый индекс, устранение N+1, сокращение внешних вызовов, пересмотр кэширования или настройка конкурентности. Для каждого изменения нужны ожидаемый эффект, тест на корректность и способ возврата назад.

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

Когда нужен Go?

Если измерения показывают ограничение в конкретном участке, Go может быть вариантом реализации. Решение о переносе принимают после сравнения с более локальными изменениями.

Что подготовить для разбора API.

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

  • Какой endpoint и какой пользовательский сценарий затронут?
  • Когда проблема появилась и от чего зависит её частота?
  • Какие метрики уже есть, а каких не хватает для решения?