Мониторинг 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)»
Запрос:
Блоги
Рекомендаций по книгам
Читайте также
Chaos Engineering для Java: как сломать приложение, чтобы оно стало сильнее
Go в 2025: полный Roadmap для разработчика от новичка до профи
Оптимизация производительности Swift приложений: советы и примеры
Сетевое программирование на Rust: пишем быстрый и безопасный TCP-сервер
Работа с файлами в PHP: от новичка до профи за 20 минут