"У нас упал прод в 3 ночи. Мы узнали об этом в 9 утра из письма клиента."
Знакомая ситуация? У меня таких историй десятки. В 2023-м я консультировал стартап на $2M ARR — у них не было ни единого алерта. Мониторинг = SSH на сервер и tail -f в логах. Когда база встала из-за переполнения диска, они потеряли 6 часов работы и $15k выручки.
Спойлер: настроить нормальный мониторинг можно за один вечер. Без Kubernetes, без DataDog за $3000/месяц, без dedicated DevOps-команды.
В этой статье — минималистичный стек для реальных проектов: Prometheus для метрик, Grafana для визуализации, Loki для логов. Всё это поднимается на одном сервере, работает годами и спасает вашу жопу в 3 ночи.
Почему мониторинг — это не роскошь
Три реальных кейса из моей практики:
Кейс 1: Fintech-стартап (2024) Клиентская база росла, API тормозил всё сильнее. Команда знала, что "что-то не так", но не знала, что именно. Поставили Prometheus за вечер — оказалось, что одна точка делала 300+ SQL-запросов на один HTTP-запрос. Пофиксили N+1, response time с 2.5s упал до 120ms. ROI мониторинга окупился за неделю.
Кейс 2: E-commerce на Django (2025) Продакшен "тупил" раз в 2-3 дня, но без паттерна. SSH + htop ничего не показывал. Добавили Grafana с метриками памяти — обнаружили, что Celery worker жрал 16GB RAM и OOM-killer убивал его. Виновник — утечка памяти в обработке картинок. Фикс занял 2 часа, простои прекратились.
Кейс 3: SaaS для B2B (2023)
Клиенты жаловались на "странные тормоза". Метрики показали spike в латентности каждые 6 часов. Loki помог найти паттерн: backup-скрипт на том же сервере выполнял pg_dump без nice, CPU утилизация летела в 100%, приложение задыхалось. Решение — перенести бэкапы на отдельную машину.
90% production-проблем невидимы без мониторинга. Вы не узнаете о них, пока не получите angry email от клиента или пока не потеряете деньги.
Что такое observability простыми словами
Observability (наблюдаемость) — способность понять, что происходит внутри системы, глядя на её внешние сигналы.
Три столпа наблюдаемости:
- Метрики (Metrics) — числовые показатели: CPU, память, RPS, latency, error rate
- Логи (Logs) — события: "пользователь зарегистрировался", "ошибка в базе", "начали деплой"
- Трейсы (Traces) — путь запроса через систему (в этой статье не покрываем, это для микросервисов)
Метафора: представьте автомобиль.
- Метрики — спидометр, тахометр, температура двигателя
- Логи — бортовой компьютер с записью "двигатель перегрелся в 14:35"
- Трейсы — видео регистратор, показывающий весь маршрут
Без мониторинга вы ведёте машину с завязанными глазами и узнаёте о поломке, когда она уже встала.
Выбор стека: почему Prometheus + Grafana + Loki
Есть десятки инструментов мониторинга. Я перепробовал Zabbix, Nagios, ELK Stack, Datadog, New Relic. Для 90% проектов выбор очевиден: Prometheus + Grafana + Loki.
Почему этот стек:
- ✅ Open source и бесплатный — никаких лицензий, vendor lock-in или счетов на $5k/месяц
- ✅ Production-grade — используется в крупнейших компаниях (Google, Uber, GitLab)
- ✅ Lightweight — работает на одном сервере с 2GB RAM
- ✅ Интеграции из коробки — exporters для всего: PostgreSQL, Redis, Nginx, Node.js
- ✅ Active development — обновления каждый месяц, огромное комьюнити
- ✅ Простота — поднимается за час, не требует PhD в DevOps
Сравнение с альтернативами:
| Критерий | Prometheus Stack | ELK Stack | Datadog/New Relic | Zabbix |
|---|---|---|---|---|
| Стоимость | ✅ Бесплатно | ✅ Бесплатно | ❌ $100-5000/мес | ✅ Бесплатно |
| Простота setup | ✅ 1-2 часа | ⚠️ 4-8 часов | ✅ 30 минут | ⚠️ 2-4 часа |
| Ресурсы (RAM) | ✅ 1-2GB | ❌ 8-16GB | ☁️ SaaS | ⚠️ 2-4GB |
| Метрики | ✅ Отлично | ⚠️ Не фокус | ✅ Отлично | ✅ Хорошо |
| Логи | ✅ Loki | ✅ Отлично (ES) | ✅ Отлично | ⚠️ Базово |
| Алерты | ✅ Alertmanager | ⚠️ Сложно | ✅ Отлично | ✅ Хорошо |
| Дашборды | ✅ Grafana | ⚠️ Kibana | ✅ Красиво | ⚠️ Kibana |
| Community & Экосистема | ✅ Огромное | ✅ Большое | ⚠️ Vendor-lock | ⚠️ Устарело |
Мой выбор:
- Для стартапов и малых проектов (до 10 серверов) — Prometheus Stack
- Для enterprise с compliance — ELK Stack (требует Elasticsearch для аудита)
- Для корпораций с деньгами — Datadog/New Relic (если бюджет есть и лень возиться)
- Для legacy-систем — Zabbix (если он уже стоит, не трогайте)
Архитектура стека на минималках
Вот что мы будем запускать:
┌─────────────────────────────────────────────────┐
│ Ваш сервер (2-4GB RAM) │
├─────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌──────────────┐ │
│ │ Ваше приложение │ │ PostgreSQL │ │
│ │ (FastAPI/Django)│ │ / Redis │ │
│ └────┬────────────┘ └────┬─────────┘ │
│ │ │ │
│ │ metrics │ metrics │
│ │ + logs │ (exporter) │
│ ▼ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ Prometheus │ │
│ │ (собирает метрики каждые 15s) │ │
│ └───────────┬─────────────────────┘ │
│ │ │
│ │ query │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ Grafana │ │
│ │ (визуализация + алерты) │ │
│ └───────────┬─────────────────────┘ │
│ │ query │
│ ┌───────────▼─────────────────────┐ │
│ │ Loki │ │
│ │ (хранит логи) │ │
│ └─────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────┘
Компоненты:
- Prometheus — time-series база данных для метрик. Ходит по HTTP к вашему приложению и exporters, забирает метрики каждые 15-30 секунд.
- Grafana — веб-интерфейс для дашбордов и алертов. Подключается к Prometheus и Loki, рисует графики.
- Loki — лог-агрегатор. Ваше приложение шлёт логи, Loki их индексирует, Grafana показывает.
- Exporters — приложения, которые экспортируют метрики в формате Prometheus:
node_exporter— метрики сервера (CPU, RAM, disk, network)postgres_exporter— метрики PostgreSQLredis_exporter— метрики Redisnginx_exporter— метрики Nginx
Требования к серверу:
- Минимум: 2GB RAM, 2 CPU cores, 20GB disk
- Рекомендуется: 4GB RAM, 2 CPU cores, 50GB disk
- OS: Ubuntu 22.04/24.04, Debian 12, или любой Linux с Docker
Этот стек я запускал даже на VPS за $5/месяц (Hetzner CX21). Для малых проектов хватает за глаза.
Практика: поднимаем стек за час
Переходим к делу. Предполагаю, что у вас есть сервер на Ubuntu/Debian с Docker.
Шаг 1: Создаём docker-compose.yml
Создайте директорию для мониторинга:
mkdir -p /opt/monitoring
cd /opt/monitoringСоздайте docker-compose.yml:
services:
# Prometheus — собирает метрики
prometheus:
image: prom/prometheus:v3.0.0
container_name: prometheus
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention.time=30d" # Храним метрики 30 дней
- "--web.enable-lifecycle" # API для hot-reload конфига
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- ./prometheus/alerts.yml:/etc/prometheus/alerts.yml
- prometheus_data:/prometheus
restart: unless-stopped
networks:
- monitoring
# Grafana — визуализация
grafana:
image: grafana/grafana:11.4.0
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=your_secure_password # ПОМЕНЯЙТЕ!
- GF_INSTALL_PLUGINS=grafana-piechart-panel
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
restart: unless-stopped
networks:
- monitoring
# Loki — логи
loki:
image: grafana/loki:3.3.2
container_name: loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- loki_data:/loki
restart: unless-stopped
networks:
- monitoring
# Node Exporter — метрики сервера
node_exporter:
image: prom/node-exporter:v1.8.2
container_name: node_exporter
command:
- "--path.rootfs=/host"
ports:
- "9100:9100"
volumes:
- /:/host:ro,rslave
restart: unless-stopped
networks:
- monitoring
volumes:
prometheus_data:
grafana_data:
loki_data:
networks:
monitoring:
driver: bridgeШаг 2: Конфигурация Prometheus
Создайте prometheus/prometheus.yml:
global:
scrape_interval: 15s # Собираем метрики каждые 15 секунд
evaluation_interval: 15s # Проверяем правила алертов каждые 15 секунд
# Алерты (создадим позже)
rule_files:
- "/etc/prometheus/alerts.yml"
# Откуда собираем метрики
scrape_configs:
# Сам Prometheus
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
# Метрики сервера (CPU, RAM, Disk)
- job_name: "node"
static_configs:
- targets: ["node_exporter:9100"]
# Ваше приложение (FastAPI, Django, etc.)
# Раскомментируйте и укажите адрес вашего приложения
# - job_name: 'app'
# static_configs:
# - targets: ['app:8000']
# PostgreSQL (если используете postgres_exporter)
# - job_name: 'postgres'
# static_configs:
# - targets: ['postgres_exporter:9187']
# Redis (если используете redis_exporter)
# - job_name: 'redis'
# static_configs:
# - targets: ['redis_exporter:9121']Создайте пустой файл алертов prometheus/alerts.yml (заполним позже):
groups:
- name: basic_alerts
interval: 30s
rules: []Шаг 3: Запускаем стек
docker compose up -dПроверяем, что всё запустилось:
docker compose psДолжны увидеть 4 контейнера в статусе Up:
prometheusgrafanalokinode_exporter
Проверяем доступность:
- Prometheus: http://your-server-ip:9090
- Grafana: http://your-server-ip:3000 (логин:
admin, пароль: изdocker-compose.yml) - Loki: http://your-server-ip:3100/ready (должен вернуть
ready)
Поздравляю! Базовый стек запущен. Теперь настраиваем дашборды и алерты.
Шаг 4: Настройка Grafana
- Откройте Grafana: http://your-server-ip:3000
- Войдите (admin / ваш пароль из docker-compose)
- Добавьте Data Source:
- Connections → Add data source → Prometheus
- URL:
http://prometheus:9090 - Save & Test — должна быть галочка "Data source is working"
- Повторите для Loki:
- Add data source → Loki
- URL:
http://loki:3100 - Save & Test
Шаг 5: Импорт готового дашборда
Не нужно рисовать дашборд с нуля — используйте готовый.
- В Grafana: Dashboards → Import
- Введите ID дашборда: 1860 (Node Exporter Full)
- Нажмите Load
- Выберите Prometheus data source
- Import
Вуаля! У вас появился дашборд с метриками сервера: CPU, RAM, Disk I/O, Network.
Другие полезные дашборды:
- PostgreSQL: ID 9628
- Redis: ID 11835
- Nginx: ID 12708
- Docker: ID 893
Добавляем метрики из вашего приложения
Теперь самое важное — метрики из вашего приложения.
Python (FastAPI / Django)
Установите библиотеку:
pip install prometheus-clientFastAPI:
from fastapi import FastAPI
from prometheus_client import Counter, Histogram, make_asgi_app
app = FastAPI()
# Метрики
REQUEST_COUNT = Counter(
'app_requests_total',
'Total HTTP requests',
['method', 'endpoint', 'status']
)
REQUEST_DURATION = Histogram(
'app_request_duration_seconds',
'HTTP request duration',
['method', 'endpoint']
)
@app.middleware("http")
async def prometheus_middleware(request, call_next):
method = request.method
endpoint = request.url.path
with REQUEST_DURATION.labels(method, endpoint).time():
response = await call_next(request)
REQUEST_COUNT.labels(method, endpoint, response.status_code).inc()
return response
# Endpoint для Prometheus
metrics_app = make_asgi_app()
app.mount("/metrics", metrics_app)Теперь метрики доступны на http://your-app:8000/metrics.
Django (с django-prometheus):
pip install django-prometheus# settings.py
INSTALLED_APPS = [
'django_prometheus',
# ...
]
MIDDLEWARE = [
'django_prometheus.middleware.PrometheusBeforeMiddleware',
# ... остальные middleware
'django_prometheus.middleware.PrometheusAfterMiddleware',
]
# urls.py
urlpatterns = [
path('', include('django_prometheus.urls')),
# ...
]Метрики на http://your-app:8000/metrics.
Node.js (Express)
npm install prom-clientconst express = require("express");
const client = require("prom-client");
const app = express();
// Создаём registry
const register = new client.Registry();
// Собираем дефолтные метрики (CPU, memory, event loop)
client.collectDefaultMetrics({ register });
// Кастомные метрики
const httpRequestDuration = new client.Histogram({
name: "http_request_duration_seconds",
help: "Duration of HTTP requests in seconds",
labelNames: ["method", "route", "status_code"],
registers: [register],
});
// Middleware для метрик
app.use((req, res, next) => {
const start = Date.now();
res.on("finish", () => {
const duration = (Date.now() - start) / 1000;
httpRequestDuration
.labels(req.method, req.route?.path || req.path, res.statusCode)
.observe(duration);
});
next();
});
// Endpoint для Prometheus
app.get("/metrics", async (req, res) => {
res.set("Content-Type", register.contentType);
res.end(await register.metrics());
});
app.listen(3000);Добавляем приложение в Prometheus
Отредактируйте prometheus/prometheus.yml:
scrape_configs:
# ... existing jobs
- job_name: "myapp"
static_configs:
- targets: ["host.docker.internal:8000"] # Ваше приложениеЕсли приложение в Docker Compose, используйте имя сервиса:
- job_name: "myapp"
static_configs:
- targets: ["myapp:8000"]Перезапустите Prometheus:
docker compose restart prometheusПроверьте в Prometheus UI: Status → Targets — ваше приложение должно быть в статусе UP.
Настройка логов с Loki
Loki собирает логи из вашего приложения.
Вариант 1: Promtail (рекомендуется)
Promtail — агент для сбора логов и отправки в Loki.
Добавьте в docker-compose.yml:
promtail:
image: grafana/promtail:3.3.2
container_name: promtail
volumes:
- /var/log:/var/log:ro # Логи системы
- ./promtail/config.yml:/etc/promtail/config.yml
- ./logs:/app/logs:ro # Логи вашего приложения
command: -config.file=/etc/promtail/config.yml
restart: unless-stopped
networks:
- monitoringСоздайте promtail/config.yml:
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
# Логи вашего приложения
- job_name: app
static_configs:
- targets:
- localhost
labels:
job: app
__path__: /app/logs/*.log
# Системные логи (опционально)
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: syslog
__path__: /var/log/syslogПерезапустите стек:
docker compose up -dВариант 2: Логирование напрямую из приложения
Python (python-logging-loki):
pip install python-logging-lokiimport logging
from logging_loki import LokiHandler
logger = logging.getLogger("my-app")
logger.setLevel(logging.INFO)
loki_handler = LokiHandler(
url="http://loki:3100/loki/api/v1/push",
tags={"application": "my-app", "environment": "production"},
version="1",
)
logger.addHandler(loki_handler)
logger.info("Application started")
logger.error("Something went wrong", extra={"user_id": 123})Просмотр логов в Grafana
- Откройте Grafana
- Explore → выберите Loki data source
- Запрос:
{job="app"} - Нажмите Run query
Вы увидите логи вашего приложения в реальном времени.
Полезные запросы Loki (LogQL):
# Все логи приложения
{job="app"}
# Только ошибки
{job="app"} |= "ERROR"
# Логи конкретного пользователя
{job="app"} | json | user_id="123"
# Rate ошибок за последние 5 минут
rate({job="app"} |= "ERROR" [5m])Алерты: чтобы не проспать падение прода
Алерты — самая важная часть мониторинга. Настроим alerting в 3 шага.
Шаг 1: Добавляем правила алертов
Отредактируйте prometheus/alerts.yml:
groups:
- name: critical_alerts
interval: 30s
rules:
# Сервер недоступен
- alert: InstanceDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Instance {{ $labels.instance }} is down"
description: "{{ $labels.job }} has been down for more than 1 minute."
# CPU больше 80%
- alert: HighCPU
expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
annotations:
summary: "High CPU usage on {{ $labels.instance }}"
description: "CPU usage is above 80% for 5 minutes (current: {{ $value }}%)"
# RAM больше 90%
- alert: HighMemory
expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
for: 5m
labels:
severity: critical
annotations:
summary: "High memory usage on {{ $labels.instance }}"
description: "Memory usage is above 90% (current: {{ $value }}%)"
# Диск больше 85%
- alert: DiskSpaceLow
expr: (1 - (node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.lxcfs"} / node_filesystem_size_bytes)) * 100 > 85
for: 10m
labels:
severity: warning
annotations:
summary: "Low disk space on {{ $labels.instance }}"
description: "Disk {{ $labels.mountpoint }} is {{ $value }}% full"
# Высокий error rate (>5% запросов с ошибками)
- alert: HighErrorRate
expr: rate(app_requests_total{status=~"5.."}[5m]) / rate(app_requests_total[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate in {{ $labels.job }}"
description: "Error rate is {{ $value | humanizePercentage }} for 5 minutes"
# Медленные запросы (p95 latency > 1s)
- alert: SlowRequests
expr: histogram_quantile(0.95, rate(app_request_duration_seconds_bucket[5m])) > 1
for: 10m
labels:
severity: warning
annotations:
summary: "Slow requests in {{ $labels.job }}"
description: "95th percentile latency is {{ $value }}s"Перезагрузите конфиг Prometheus:
curl -X POST http://localhost:9090/-/reloadПроверьте алерты: http://your-server-ip:9090/alerts
Шаг 2: Настройка Alertmanager (уведомления)
Alertmanager отправляет уведомления в Telegram, Slack, email и т.д.
Добавьте в docker-compose.yml:
alertmanager:
image: prom/alertmanager:v0.27.0
container_name: alertmanager
ports:
- "9093:9093"
volumes:
- ./alertmanager/config.yml:/etc/alertmanager/config.yml
- alertmanager_data:/alertmanager
command:
- "--config.file=/etc/alertmanager/config.yml"
restart: unless-stopped
networks:
- monitoring
volumes:
# ... existing volumes
alertmanager_data:Отредактируйте prometheus/prometheus.yml:
# Добавьте в начало файла
alerting:
alertmanagers:
- static_configs:
- targets: ["alertmanager:9093"]Создайте alertmanager/config.yml:
global:
resolve_timeout: 5m
route:
group_by: ["alertname", "cluster"]
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: "telegram"
receivers:
# Telegram (рекомендуется)
- name: "telegram"
telegram_configs:
- bot_token: "YOUR_BOT_TOKEN" # Получите у @BotFather
chat_id: YOUR_CHAT_ID # Ваш chat_id
parse_mode: "HTML"
message: |
<b>{{ .Status | toUpper }}</b>
{{ range .Alerts }}
<b>Alert:</b> {{ .Labels.alertname }}
<b>Severity:</b> {{ .Labels.severity }}
<b>Summary:</b> {{ .Annotations.summary }}
<b>Description:</b> {{ .Annotations.description }}
{{ end }}
# Slack (альтернатива)
# - name: 'slack'
# slack_configs:
# - api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
# channel: '#alerts'
# title: 'Alert: {{ .GroupLabels.alertname }}'
# text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
# Email (альтернатива)
# - name: 'email'
# email_configs:
# - to: 'your-email@example.com'
# from: 'alerts@yourapp.com'
# smarthost: 'smtp.gmail.com:587'
# auth_username: 'your-email@gmail.com'
# auth_password: 'your-app-password'Перезапустите стек:
docker compose up -dКак получить Telegram bot token и chat_id:
- Создайте бота: напишите @BotFather →
/newbot→ следуйте инструкциям → получитеbot_token - Узнайте chat_id: напишите боту
/start, затем откройтеhttps://api.telegram.org/bot<bot_token>/getUpdates→ найдите"chat":{"id":123456789}
Шаг 3: Тестируем алерты
Создадим искусственную нагрузку для теста:
# Загружаем CPU
yes > /dev/null &
yes > /dev/null &
yes > /dev/null &
yes > /dev/null &
# Через 5 минут должен сработать алерт HighCPU
# Проверьте: http://your-server-ip:9090/alerts
# Остановите нагрузку:
killall yesВы должны получить уведомление в Telegram в течение 5-6 минут.
Алерты работают! Теперь вы узнаете о проблемах раньше, чем клиенты.
Дашборды для реальной жизни
Готовые дашборды — это хорошо, но для production нужны кастомные.
Дашборд "Application Health"
Создайте новый дашборд в Grafana:
Панели:
-
RPS (Requests Per Second)
- Query:
rate(app_requests_total[1m]) - Визуализация: Graph
- Query:
-
Error Rate (%)
- Query:
(rate(app_requests_total{status=~"5.."}[5m]) / rate(app_requests_total[5m])) * 100 - Визуализация: Graph
- Threshold: warning при 1%, critical при 5%
- Query:
-
Latency (p50, p95, p99)
- Query:
histogram_quantile(0.50, rate(app_request_duration_seconds_bucket[5m])) # p50 histogram_quantile(0.95, rate(app_request_duration_seconds_bucket[5m])) # p95 histogram_quantile(0.99, rate(app_request_duration_seconds_bucket[5m])) # p99 - Визуализация: Graph
- Query:
-
Active Users (если есть метрика)
- Query:
active_users_gauge - Визуализация: Stat
- Query:
-
Top 5 Slowest Endpoints
- Query:
topk(5, histogram_quantile(0.95, rate(app_request_duration_seconds_bucket[5m]))) - Визуализация: Table
- Query:
Дашборд "Infrastructure"
-
CPU Usage
- Query:
100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
- Query:
-
Memory Usage
- Query:
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
- Query:
-
Disk I/O
- Query:
rate(node_disk_read_bytes_total[5m])иrate(node_disk_written_bytes_total[5m])
- Query:
-
Network Traffic
- Query:
rate(node_network_receive_bytes_total[5m])иrate(node_network_transmit_bytes_total[5m])
- Query:
Troubleshooting: как расследовать проблемы
Вы получили алерт в 3 ночи. Что делать?
Сценарий 1: HighCPU alert
- Grafana → дашборд Infrastructure → смотрим CPU график
- Correlate: смотрим RPS в это же время — если spike в трафике, виноват код
- Logs in Loki:
{job="app"} | json | line_format "{{.endpoint}} {{.duration}}"— ищем медленные эндпоинты - Prometheus:
topk(5, rate(app_request_duration_seconds_sum[5m]))— топ медленных запросов - Fix: оптимизируем код или масштабируем
Сценарий 2: HighMemory alert
- Grafana → Infrastructure → Memory Usage
- Prometheus:
process_resident_memory_bytes— смотрим потребление памяти приложением - Logs:
{job="app"} |= "OutOfMemory"или|= "MemoryError" - Hypothesis: утечка памяти? Проверяем код
- Temporary fix:
docker compose restart app - Long-term fix: профилируем код (memory_profiler, py-spy)
Сценарий 3: HighErrorRate alert
- Grafana → Application Health → Error Rate график
- Prometheus:
rate(app_requests_total{status=~"5.."}[5m])— какие эндпоинты? - Loki:
{job="app"} |= "ERROR" or "Exception"— читаем стектрейсы - Root cause: база недоступна? API упал? Timeout?
- Fix: в зависимости от причины
Сценарий 4: SlowRequests alert
- Prometheus:
histogram_quantile(0.95, rate(app_request_duration_seconds_bucket[5m]))by endpoint - Loki: находим конкретные медленные запросы с параметрами
- Database: проверяем
pg_stat_statements— может быть, slow query? - Fix: добавляем индексы, кешируем, оптимизируем
Pro tip: создайте Runbook для каждого алерта. Документ с шагами расследования и типичными решениями. Сохранит часы времени в 3 ночи.
Best Practices: что я усвоил за годы
1. Retention Policy
По умолчанию Prometheus хранит метрики 15 дней. Это мало. Установите 30-90 дней:
command:
- "--storage.tsdb.retention.time=90d"Для Loki:
# loki-config.yaml
limits_config:
retention_period: 30d2. Не мониторьте всё подряд
Метрики стоят памяти и диска. Мониторьте только то, что помогает принимать решения:
- ✅ Мониторить: RPS, error rate, latency, CPU, RAM, disk
- ❌ Не мониторить: количество кликов на каждую кнопку (это для аналитики, не observability)
3. Гигиена оповещений
- Группируйте алерты: не шлите 50 уведомлений за минуту, группируйте по 1 каждые 5 минут
- Severity levels:
critical→ звонок,warning→ Telegram,info→ только логи - Mute when deploying: во время деплоя отключайте алерты, иначе false positives
4. Backup конфигов
Храните конфиги в Git:
git init
git add docker-compose.yml prometheus/ grafana/ alertmanager/
git commit -m "Initial monitoring setup"
git remote add origin git@github.com:yourname/monitoring-config.git
git push5. Security
- Не открывайте порты наружу: используйте Nginx reverse proxy с auth
- Смените дефолтный пароль Grafana
- Ограничьте доступ к Prometheus: он может показать чувствительные данные
Продвинутые фишки
Remote Write (долгосрочное хранение)
Prometheus хранит метрики локально. Для долгосрочного хранения (годы) используйте remote write в:
- Thanos — open source, S3-backed storage
- Cortex — мультитенантный Prometheus
- Grafana Cloud — managed (бесплатно до 10k series)
ServiceMonitor (для Kubernetes)
Если у вас Kubernetes, используйте Prometheus Operator + ServiceMonitor:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
endpoints:
- port: metrics
interval: 30sDistributed Tracing (Tempo)
Для микросервисов добавьте Grafana Tempo:
tempo:
image: grafana/tempo:latest
command: ["-config.file=/etc/tempo.yaml"]
volumes:
- ./tempo.yaml:/etc/tempo.yaml
ports:
- "3200:3200" # Tempo UI
- "4317:4317" # OTLP gRPCИнтегрируйте с OpenTelemetry SDK в приложении.
Стоимость владения
Реальные цифры из моей практики:
Стоимость self-hosted стека (в месяц):
- VPS 4GB RAM (Hetzner CX31): $7
- Хранилище 50GB (если нужно больше): $5
- Время на setup: 4-8 часов (один раз)
- Время на поддержку: 1-2 часа в месяц
Итого: $12-15/месяц + 2 часа времени
Стоимость SaaS-альтернатив:
- Datadog: $100-500/месяц (зависит от объёма)
- New Relic: $99-749/месяц
- Grafana Cloud: $0-299/месяц (free tier до 10k series)
ROI: за 3 месяца экономия $300-1500. За год — $1200-6000.
Но главная экономия — не потерянная выручка из-за простоев. Один даунтайм на час может стоить $1000-10000 в зависимости от проекта.
Мониторинг окупается после первого инцидента, который вы предотвратили. У меня это была первая неделя.
Выводы
Что мы сделали:
- Подняли Prometheus + Grafana + Loki за час
- Настроили метрики приложения и инфраструктуры
- Создали алерты с уведомлениями в Telegram
- Построили дашборды для мониторинга и troubleshooting
- Научились расследовать проблемы
Что дальше:
- Добавьте метрики из всех критичных компонентов: база данных, кеш, очереди, внешние API
- Настройте алерты под ваш SLA: если у вас 99.9% uptime, downtime > 43 минуты в месяц — критичен
- Создайте runbook для каждого алерта: документ "что делать, если..."
- Обучите команду: все должны уметь читать метрики и логи
- Автоматизируйте: добавьте мониторинг в CI/CD, чтобы метрики появлялись автоматически
Главный урок:
Мониторинг — это не опция, а необходимость. Чем раньше вы его настроите, тем больше нервов, денег и клиентов сохраните.
Не ждите, пока production упадёт в 3 ночи. Настройте мониторинг прямо сейчас.
P.S. У вас вопросы по настройке мониторинга для вашего проекта? Пишите в комментарии или на email — помогу разобраться.

