Мониторинг Rust приложений: метрики и алерты от А до Я

Онлайн-тренажер Python для начинающих

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

Начать курс

Мониторинг Rust приложений: метрики и алерты от А до Я

Когда ваше Rust-приложение выходит в продакшен, код перестаёт быть просто кодом. Он становится сервисом, от которого зависят пользователи и бизнес. Без мониторинга вы летите вслепую: сбои обнаруживаются по жалобам, а производительность оценивается «на глаз». В этой статье мы разберём, как построить полноценную систему мониторинга для Rust — от сбора базовых метрик до настройки алертов в Prometheus и визуализации в Grafana.

1. Почему мониторинг важен для Rust-проектов

Rust славится производительностью и безопасностью памяти, но это не отменяет необходимости следить за приложением. Типичные проблемы в продакшене:

  • Утечки памяти (например, через Arc или циклические ссылки).
  • Блокировки в async-коде (deadlocks или starvation в tokio).
  • Неожиданные паники (даже с catch_unwind).
  • Деградация производительности из-за неоптимальных алгоритмов.

Мониторинг даёт ответы на вопросы: «Что сейчас происходит?», «Почему это произошло?» и «Как это предотвратить?».

2. Сбор метрик: библиотека metrics и экспорт в Prometheus

Стандартный стек для Rust — крейт metrics (или prometheus). Мы используем metrics, так как он абстрагирует экспорт и легко меняет бэкенд.

2.1. Установка и базовая настройка

Добавьте зависимости в Cargo.toml:

[dependencies]
metrics = "0.21"
metrics-exporter-prometheus = "0.12"
tokio = { version = "1", features = ["full"] }

Создаём простой HTTP-сервер для эндпоинта /metrics:

use metrics_exporter_prometheus::PrometheusBuilder;
use std::net::SocketAddr;
use tokio::net::TcpListener;

#[tokio::main]
async fn main() {
    // Инициализируем экспортёр Prometheus
    let (recorder, exporter) = PrometheusBuilder::new()
        .build()
        .expect("Не удалось создать Prometheus экспортёр");

    metrics::set_boxed_recorder(Box::new(recorder))
        .expect("Не удалось установить глобальный рекордер");

    // Запускаем сервер метрик
    let addr: SocketAddr = "0.0.0.0:9090".parse().unwrap();
    let listener = TcpListener::bind(addr).await.unwrap();
    println!("Метрики доступны на http://{}", addr);

    loop {
        let (mut stream, _) = listener.accept().await.unwrap();
        let body = exporter.encode().unwrap();
        let response = format!(
            "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: {}\r\n\r\n{}",
            body.len(),
            body
        );
        tokio::io::AsyncWriteExt::write_all(&mut stream, response.as_bytes())
            .await
            .unwrap();
    }
}

2.2. Регистрация кастомных метрик

Добавим счётчик запросов и гистограмму времени ответа:

use metrics::{counter, histogram, increment_counter};
use std::time::Instant;

async fn handle_request() {
    let start = Instant::now();

    // Ваша бизнес-логика
    tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;

    // Записываем метрики
    increment_counter!("http_requests_total", "method" => "GET");
    histogram!("http_request_duration_seconds", start.elapsed().as_secs_f64(), "method" => "GET");
}

Теперь на /metrics вы увидите:

# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET"} 1
# HELP http_request_duration_seconds HTTP request duration
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{method="GET",le="0.005"} 0
http_request_duration_seconds_bucket{method="GET",le="0.01"} 0
http_request_duration_seconds_bucket{method="GET",le="0.025"} 0
http_request_duration_seconds_bucket{method="GET",le="0.05"} 1
http_request_duration_seconds_bucket{method="GET",le="+Inf"} 1
http_request_duration_seconds_sum{method="GET"} 0.050123
http_request_duration_seconds_count{method="GET"} 1

3. Алерты: настройка Prometheus и Alertmanager

Метрики бесполезны, если вы не узнаёте о проблемах мгновенно. Настроим алерты.

3.1. Конфигурация Prometheus (prometheus.yml)

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'rust_app'
    static_configs:
      - targets: ['localhost:9090']

3.2. Правила алертов (alerts.yml)

groups:
  - name: rust_app_alerts
    rules:
      - alert: HighErrorRate
        expr: rate(http_requests_total[5m]) > 100
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Высокая частота запросов ({{ $value }})"
          description: "Приложение обрабатывает более 100 запросов в секунду"

      - alert: SlowResponses
        expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.5
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "Медленные ответы (p95 > 500ms)"
          description: "95-й перцентиль времени ответа превысил 0.5 секунды"

3.3. Настройка Alertmanager

Укажите получателя (например, email или Slack) в alertmanager.yml:

route:
  receiver: 'slack'

receivers:
  - name: 'slack'
    slack_configs:
      - api_url: 'https://hooks.slack.com/services/ВАШ_ТОКЕН'
        channel: '#alerts-rust'

4. Визуализация в Grafana

Создадим дашборд для быстрого анализа.

4.1. Панель «RPS (Requests Per Second)»

Запрос:


                
                

Блоги

Рекомендаций по книгам