Перейти к основному содержимому

1.23. Метрики производительности системы

Разработчику Аналитику Архитектору

Метрики производительности системы

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

Как система (фронтенд и бэкенд) собираются в одно целое

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

Бэкенд — это серверная часть системы, которая хранит данные, реализует бизнес-логику, управляет доступом к ресурсам и обеспечивает безопасность. Бэкенд принимает запросы от фронтенда, обрабатывает их, обращается к базам данных, внешним сервисам или внутренним модулям, формирует ответ и отправляет его обратно клиенту.

Связь между фронтендом и бэкендом осуществляется через сетевые протоколы, чаще всего через HTTP или WebSocket. Фронтенд формирует структурированный запрос — например, в формате JSON — и отправляет его на определённый адрес (endpoint) бэкенда. Бэкенд парсит этот запрос, проверяет авторизацию, выполняет необходимые действия и возвращает результат. Этот цикл может повторяться десятки раз в течение одного сеанса работы пользователя.

Для того чтобы система функционировала как единое целое, необходимо соблюдать согласованность в форматах данных, версионировании API, обработке ошибок и управлении состоянием. Современные подходы, такие как REST, GraphQL или gRPC, задают правила этого взаимодействия. Инструменты сборки, контейнеризации и оркестрации (например, Docker и Kubernetes) обеспечивают совместную развёртку и масштабирование компонентов. Мониторинг и логирование позволяют отслеживать работу всей системы в реальном времени, выявлять узкие места и предотвращать сбои.

Таким образом, фронтенд и бэкенд образуют единую систему не за счёт физического объединения, а благодаря чётко определённым интерфейсам, протоколам и процессам взаимодействия. Эффективность этой системы измеряется с помощью метрик производительности.

Что такое метрика

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

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

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

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

Зачем нужны метрики производительности системы

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

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

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

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

Наконец, метрики производительности формируют основу для Service Level Objectives (SLO) — целевых показателей, которые определяют ожидаемое качество сервиса. Например, SLO может гласить: «99% запросов должны обрабатываться менее чем за 500 миллисекунд». Метрики позволяют измерять выполнение таких обязательств и информировать заинтересованные стороны о состоянии системы.

Метрики производительности системы

Существует множество метрик, характеризующих производительность системы. Наиболее важные из них — QPS, TPS, Concurrency и Response Time. Каждая из них отражает отдельный аспект поведения системы и используется в зависимости от контекста и целей анализа.

QPS (Queries Per Second)

QPS — это количество запросов, которые система получает и обрабатывает за одну секунду. Эта метрика применяется преимущественно к веб-сервисам и API, где каждый входящий HTTP-запрос считается отдельной операцией.

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

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

TPS (Transactions Per Second)

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

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

Пример: при оформлении заказа в интернет-магазине одна транзакция может включать проверку наличия товара, списание средств, создание записи в базе и отправку email. Даже если для этого потребовалось пять HTTP-запросов, с точки зрения TPS это одна транзакция.

Concurrency (Уровень одновременных запросов)

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

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

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

Response Time (Время ответа)

Response Time — это интервал времени между моментом получения запроса и моментом отправки ответа. Эта метрика напрямую влияет на восприятие пользователем скорости работы системы.

Время ответа обычно анализируется не как одно среднее значение, а как распределение: медиана (50-й перцентиль), 90-й, 95-й и 99-й перцентили. Это позволяет увидеть не только типичное поведение, но и худшие случаи, которые могут сильно влиять на опыт отдельных пользователей.

Пример: если медианное время ответа составляет 100 мс, но 99-й перцентиль — 5000 мс, это означает, что 1% пользователей сталкивается с серьёзными задержками, хотя большинство работает быстро.


Ниже приведена таблица, обобщающая основные метрики производительности:

МетрикаОписаниеТипичное применение
QPSКоличество запросов в секундуВеб-API, микросервисы, CDN
TPSКоличество завершённых транзакций в секундуБанковские системы, e-commerce
ConcurrencyКоличество одновременно обрабатываемых запросовСерверы приложений, базы данных
Response TimeВремя между запросом и ответомВсе типы интерактивных систем

Примеры кода для измерения метрик в разных языках:

Python (Flask)

from flask import Flask, request, g
import time

app = Flask(__name__)

@app.before_request
def start_timer():
g.start_time = time.time()

@app.after_request
def log_response_time(response):
duration = time.time() - g.start_time
print(f"Response time: {duration:.3f} seconds")
return response

@app.route('/api/data')
def get_data():
# Имитация обработки
time.sleep(0.1)
return {"status": "ok"}

Java (Spring Boot)

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestController
public class MetricsController {

private static final Logger logger = LoggerFactory.getLogger(MetricsController.class);

@GetMapping("/api/info")
public String getInfo() {
long start = System.currentTimeMillis();
try {
Thread.sleep(100); // имитация работы
return "OK";
} finally {
long duration = System.currentTimeMillis() - start;
logger.info("Response time: {} ms", duration);
}
}
}

C# (ASP.NET Core)

using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;

[ApiController]
[Route("api/[controller]")]
public class PerformanceController : ControllerBase
{
[HttpGet("check")]
public IActionResult Check()
{
var stopwatch = Stopwatch.StartNew();
System.Threading.Thread.Sleep(100); // имитация обработки
stopwatch.Stop();

Console.WriteLine($"Response time: {stopwatch.ElapsedMilliseconds} ms");
return Ok(new { status = "healthy" });
}
}

Эти примеры демонстрируют базовый подход к измерению времени ответа. В реальных системах такие метрики обычно отправляются в специализированные системы мониторинга, такие как Prometheus, Grafana, Datadog или New Relic, где они агрегируются, визуализируются и используются для автоматического оповещения.


Перцентили и распределение времени ответа

Среднее значение времени ответа — удобная, но обманчивая метрика. Оно скрывает детали распределения и может давать ложное ощущение стабильности. Например, если 99% запросов обрабатываются за 50 миллисекунд, а 1% — за 10 секунд, среднее время ответа составит около 150 миллисекунд. Такой показатель выглядит приемлемым, хотя каждый сотый пользователь сталкивается с серьёзной задержкой.

Для более точной оценки используются перцентили (percentiles). Перцентиль показывает, какая доля запросов уложилась в определённое время. Наиболее распространены следующие значения:

  • P50 (медиана) — половина запросов обработана быстрее этого значения.
  • P90 — 90% запросов обработано быстрее этого значения.
  • P95 — 95% запросов обработано быстрее этого значения.
  • P99 — 99% запросов обработано быстрее этого значения.

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

График распределения времени ответа (histogram) позволяет визуализировать форму распределения: есть ли длинный «хвост» медленных запросов, насколько резко возрастает время при увеличении нагрузки, присутствуют ли аномальные пики. Такие графики помогают выявлять проблемы, которые не видны при анализе только средних значений.

Сквозная трассировка (Distributed Tracing)

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

Сквозная трассировка решает эту задачу. Каждому входящему запросу присваивается уникальный идентификатор (trace ID). Все внутренние вызовы, порождённые этим запросом, помечаются тем же идентификатором и дополнительными данными (span ID, parent span ID), что позволяет восстановить полное дерево вызовов.

Каждый компонент записывает временные метки начала и окончания своей работы, а также контекст: имя операции, параметры, ошибки, используемые ресурсы. Эти данные отправляются в централизованную систему трассировки, такую как Jaeger, Zipkin или AWS X-Ray.

Результат — интерактивная диаграмма, где можно увидеть:

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

Трассировка особенно полезна при диагностике сложных инцидентов, когда проблема возникает не в одном сервисе, а на стыке нескольких компонентов.

Влияние инфраструктуры на метрики

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

Основные инфраструктурные метрики, влияющие на производительность:

  • Загрузка CPU — высокая загрузка процессора приводит к увеличению времени выполнения операций и очередей задач.
  • Использование памяти — нехватка оперативной памяти вызывает подкачку на диск (swapping), что резко замедляет работу.
  • Дисковый I/O — медленные операции чтения/записи на диск (особенно на HDD) создают узкие места при работе с файлами или базами данных.
  • Сетевая задержка и пропускная способность — высокая latency между сервисами или ограниченная bandwidth снижают общую отзывчивость системы.
  • Количество соединений — исчерпание лимита соединений к базе данных или внешнему API блокирует новые запросы.

Эти метрики собираются на уровне хоста (сервера, виртуальной машины, контейнера) с помощью агентов мониторинга, таких как Prometheus Node Exporter, Telegraf или CloudWatch Agent. Они коррелируются с прикладными метриками (QPS, Response Time), чтобы выявить корневую причину проблем.

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

Методы сбора и хранения метрик

Сбор метрик начинается с инструментирования кода. Современные фреймворки и библиотеки предоставляют встроенные средства для экспорта метрик:

  • В Python — библиотеки prometheus_client, statsd.
  • В Java — Micrometer, Dropwizard Metrics.
  • В C#System.Diagnostics.Metrics, OpenTelemetry SDK.
  • В Node.jsprom-client, node-statsd.

Метрики могут собираться двумя способами:

  1. Push-модель: приложение само отправляет метрики в центральный сервер (например, StatsD, Datadog).
  2. Pull-модель: сервер мониторинга периодически опрашивает приложение по HTTP-эндпоинту (например, /metrics в Prometheus).

После сбора метрики сохраняются в специализированных временных базах данных (Time Series Databases), таких как:

  • Prometheus
  • InfluxDB
  • Graphite
  • VictoriaMetrics
  • Amazon Timestream

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

На основе сохранённых метрик строятся дашборды (Grafana, Kibana), настраиваются алерты (Alertmanager, PagerDuty) и формируются отчёты. Это позволяет не только реагировать на инциденты, но и проводить проактивный анализ: выявлять тренды, планировать масштабирование, оценивать влияние изменений.


Пример инструментирования на Python с использованием Prometheus:

from prometheus_client import Counter, Histogram, start_http_server
from flask import Flask, request
import time

app = Flask(__name__)

# Определение метрик
REQUEST_COUNT = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint'])
REQUEST_LATENCY = Histogram('http_request_duration_seconds', 'HTTP request duration', ['method', 'endpoint'])

@app.route('/api/data')
def get_data():
REQUEST_COUNT.labels(method='GET', endpoint='/api/data').inc()
with REQUEST_LATENCY.labels(method='GET', endpoint='/api/data').time():
# Имитация работы
time.sleep(0.1)
return {"result": "success"}

if __name__ == '__main__':
# Запуск эндпоинта /metrics на порту 8000
start_http_server(8000)
app.run(port=5000)

После запуска приложения метрики будут доступны по адресу http://localhost:8000/metrics в формате:

# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",endpoint="/api/data"} 5.0

# HELP http_request_duration_seconds HTTP request duration
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{method="GET",endpoint="/api/data",le="0.1"} 4.0
http_request_duration_seconds_bucket{method="GET",endpoint="/api/data",le="0.2"} 5.0
http_request_duration_seconds_bucket{method="GET",endpoint="/api/data",le="+Inf"} 5.0
http_request_duration_seconds_sum{method="GET",endpoint="/api/data"} 0.512
http_request_duration_seconds_count{method="GET",endpoint="/api/data"} 5.0

Эти данные могут быть собраны Prometheus и визуализированы в Grafana, где можно строить графики QPS, среднего времени ответа, перцентилей и коррелировать их с инфраструктурными метриками.