Prometheus метрики в Rust: мониторинг производительности и отказоустойчивости
В современной разработке бэкенд-приложений на Rust мониторинг стал неотъемлемой частью production-инфраструктуры. Prometheus — стандарт де-факто для сбора и хранения метрик, а его интеграция с Rust позволяет отслеживать производительность, загрузку CPU, количество запросов, ошибок и многое другое. В этой статье мы рассмотрим две основные библиотеки: prometheus (официальный клиент) и metrics + metrics-exporter-prometheus (более абстрактный подход).
Зачем нужны метрики в Rust?
Метрики позволяют:
- Отслеживать состояние сервиса в реальном времени
- Обнаруживать узкие места (latency, ошибки)
- Строить дашборды в Grafana
- Настраивать алерты (например, при падении QPS или росте ошибок)
Установка и настройка библиотеки prometheus
Добавьте в Cargo.toml:
[dependencies]
prometheus = { version = "0.13", features = ["process"] }
actix-web = "4" # для примера с веб-сервером
tokio = { version = "1", features = ["full"] }
Библиотека prometheus предоставляет три основных типа метрик: Counter, Gauge, Histogram.
Пример: создание и регистрация метрик
use prometheus::{Counter, Gauge, Histogram, HistogramOpts, Opts, Registry};
fn main() {
// Создаём реестр метрик
let registry = Registry::new();
// Counter — счётчик запросов
let request_counter = Counter::with_opts(
Opts::new("http_requests_total", "Total HTTP requests")
.const_label("service", "my_app")
).unwrap();
registry.register(Box::new(request_counter.clone())).unwrap();
// Gauge — текущее количество активных соединений
let active_connections = Gauge::with_opts(
Opts::new("active_connections", "Number of active connections")
).unwrap();
registry.register(Box::new(active_connections.clone())).unwrap();
// Histogram — распределение времени ответа
let request_duration = Histogram::with_opts(
HistogramOpts::new("http_request_duration_seconds", "Request duration in seconds")
.buckets(vec![0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0])
).unwrap();
registry.register(Box::new(request_duration.clone())).unwrap();
// Имитация использования
request_counter.inc();
active_connections.set(42.0);
request_duration.observe(0.123);
}
Экспорт метрик через HTTP (actix-web)
Чтобы Prometheus мог собирать метрики, нужно отдать их в формате /metrics:
use actix_web::{web, App, HttpServer, HttpResponse, Responder};
use prometheus::{Encoder, TextEncoder, Registry};
use std::sync::Arc;
async fn metrics_handler(registry: web::Data<Arc<Registry>>) -> impl Responder {
let encoder = TextEncoder::new();
let mut buffer = Vec::new();
encoder.encode(®istry.gather(), &mut buffer).unwrap();
HttpResponse::Ok()
.content_type("text/plain; charset=utf-8")
.body(buffer)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let registry = Arc::new(Registry::new());
// ... регистрируем метрики как выше ...
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(registry.clone()))
.route("/metrics", web::get().to(metrics_handler))
})
.bind("127.0.0.1:9090")?
.run()
.await
}
Библиотека metrics — высокоуровневый подход
Альтернатива — крейт metrics с экспортёром metrics-exporter-prometheus. Он предоставляет макросы для быстрого создания метрик:
[dependencies]
metrics = "0.21"
metrics-exporter-prometheus = "0.12"
use metrics::{counter, gauge, histogram};
use metrics_exporter_prometheus::PrometheusBuilder;
fn main() {
// Устанавливаем экспортёр Prometheus
let (recorder, exporter) = PrometheusBuilder::new()
.build()
.expect("failed to build prometheus exporter");
metrics::set_boxed_recorder(Box::new(recorder)).unwrap();
// Используем макросы
counter!("http_requests_total", 1, "service" => "my_app");
gauge!("active_connections", 42.0);
histogram!("http_request_duration_seconds", 0.123);
// Запускаем HTTP сервер для экспорта (отдельный поток)