← Назад к вопросам
Как организовывался мониторинг системы?
2.0 Middle🔥 71 комментариев
#DevOps и инфраструктура
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как организовывается мониторинг системы
Мониторинг — критическая часть production систем. За 10+ лет работы я создавал мониторинг для систем с миллионами запросов в день. Расскажу о своем подходе.
1. Стратегия мониторинга
"""
Уровни мониторинга (от критического к деталям):
1. ALERTS — критичные метрики (красные флаги)
- Сервис недоступен
- Ошибки в production
- БД недоступна
- High response time (>1s)
2. METRICS — основные показатели
- Request rate (RPS)
- Error rate
- Response time (p50, p95, p99)
- Database queries
- Cache hit rate
3. LOGS — детальная информация
- Request/response трассировка
- Exception стэки
- Business events
4. TRACES — full request journey
- Каждая функция, каждый микросервис
- Временные затраты на каждый шаг
"""
2. Система логирования
import logging
import json
from datetime import datetime
# Структурированное логирование
class JSONFormatter(logging.Formatter):
def format(self, record):
log_data = {
'timestamp': datetime.utcnow().isoformat(),
'level': record.levelname,
'logger': record.name,
'message': record.getMessage(),
'path': f'{record.pathname}:{record.lineno}',
}
# Добавляем exception если есть
if record.exc_info:
log_data['exception'] = self.formatException(record.exc_info)
return json.dumps(log_data)
# Настройка логирования
logger = logging.getLogger('myapp')
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
# Использование
logger.info('User logged in', extra={
'user_id': 123,
'ip': '192.168.1.1',
'timestamp': datetime.utcnow().isoformat()
})
# Вывод в системе логирования будет:
# {"timestamp": "2024-01-15T...", "level": "INFO", "message": "User logged in", ...}
3. Метрики с Prometheus
from prometheus_client import Counter, Histogram, Gauge, start_http_server
import time
# Счетчик запросов
request_count = Counter(
'http_requests_total',
'Total HTTP requests',
['method', 'endpoint', 'status']
)
# Время ответа
response_time = Histogram(
'http_request_duration_seconds',
'HTTP request latency',
['method', 'endpoint'],
buckets=(0.1, 0.5, 1.0, 2.0, 5.0) # Распределение по интервалам
)
# Текущий размер очереди
queue_size = Gauge(
'queue_size',
'Current size of processing queue'
)
# Использование в middleware
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
import time
app = FastAPI()
class MetricsMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
start = time.time()
response = await call_next(request)
# Записываем метрики
duration = time.time() - start
request_count.labels(
method=request.method,
endpoint=request.url.path,
status=response.status_code
).inc()
response_time.labels(
method=request.method,
endpoint=request.url.path
).observe(duration)
return response
app.add_middleware(MetricsMiddleware)
# Prometheus будет скрейпить /metrics endpoint автоматически
start_http_server(8000) # Метрики доступны на :8000/metrics
4. Трассировка (Tracing) с Jaeger
from jaeger_client import Config
from opentelemetry import trace, metrics
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
# Инициализация Jaeger
jaeger_exporter = JaegerExporter(
agent_host_name="localhost",
agent_port=6831,
)
trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(
SimpleSpanProcessor(jaeger_exporter)
)
tracer = trace.get_tracer(__name__)
# Использование spans в коде
def process_request(request_id):
with tracer.start_as_current_span('process_request') as span:
span.set_attribute('request_id', request_id)
# Вложенный span
with tracer.start_as_current_span('fetch_user_data') as child_span:
child_span.set_attribute('operation', 'database_query')
user = fetch_user(request_id)
# Другой вложенный span
with tracer.start_as_current_span('validate_data'):
validate(user)
return user
# Jaeger визуализирует цепь вызовов и показывает:
# - Общее время: 100ms
# - fetch_user_data: 50ms
# - validate_data: 10ms
# - другое: 40ms
5. Алертинг
from alertmanager_client.client import AlertManagerClient
class AlertManager:
def __init__(self):
self.client = AlertManagerClient(['http://alertmanager:9093'])
def send_alert(self, alert_name, severity='warning', description=''):
"""Отправляет alert в AlertManager"""
alert = {
'labels': {
'alertname': alert_name,
'severity': severity,
'service': 'myapp',
},
'annotations': {
'description': description,
'dashboard': 'https://grafana.example.com/...',
}
}
self.client.send_alert(alert)
alert_manager = AlertManager()
# Примеры алертов
def check_system_health():
# Проверяем здоровье
if not database.is_alive():
alert_manager.send_alert(
'DatabaseDown',
severity='critical',
description='Database connection failed'
)
if error_rate > 0.05: # 5% ошибок
alert_manager.send_alert(
'HighErrorRate',
severity='warning',
description=f'Error rate is {error_rate:.1%}'
)
if response_time.p99 > 5.0: # p99 latency > 5s
alert_manager.send_alert(
'HighLatency',
severity='warning',
description=f'p99 latency is {response_time.p99:.2f}s'
)
# Запускаем проверки периодически
import schedule
import time
schedule.every(1).minute.do(check_system_health)
while True:
schedule.run_pending()
time.sleep(1)
6. Dashboard в Grafana
"""
Типичный dashboard содержит:
1. RED метрики (Google's key metrics):
- Rate — requests per second
- Errors — error count/percentage
- Duration — latency (p50, p95, p99)
2. USE метрики (для ресурсов):
- Utilization — % используется ресурса
- Saturation — очереди ожидания
- Errors — ошибки доступа
3. Business метрики:
- User count
- Revenue
- Conversion rate
- API calls
Примеры PromQL запросов:
# Requests per second
rate(http_requests_total[5m])
# Error rate
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
# Response time percentiles
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# Database connection pool utilization
db_connection_pool_active / db_connection_pool_max
"""
7. Log Aggregation (ELK Stack)
from pythonjsonlogger import jsonlogger
import logging
from pythonjson.ext.elasticsearch import ElasticsearchHandler
# Логирование в Elasticsearch через Logstash/Filebeat
logger = logging.getLogger('myapp')
# JSON логирование для парсинга Logstash
json_handler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter()
json_handler.setFormatter(formatter)
logger.addHandler(json_handler)
# Использование
logger.info('API request', extra={
'user_id': 123,
'endpoint': '/api/users',
'method': 'GET',
'status': 200,
'duration_ms': 45,
'request_id': 'abc-123-def-456' # для correlation
})
# Kibana позволяет:
# - Искать логи по всем полям
# - Фильтровать по request_id
# - Анализировать тренды
# - Создавать алерты
8. Health Checks
from fastapi import FastAPI, HTTPException
app = FastAPI()
class HealthChecker:
def __init__(self):
self.checks = {}
def register(self, name, check_func):
"""Регистрирует функцию проверки"""
self.checks[name] = check_func
async def check_all(self):
"""Запускает все проверки"""
results = {}
for name, check_func in self.checks.items():
try:
results[name] = {
'status': 'ok',
'message': await check_func() if asyncio.iscoroutinefunction(check_func) else check_func()
}
except Exception as e:
results[name] = {
'status': 'failed',
'message': str(e)
}
return results
health_checker = HealthChecker()
# Регистрируем проверки
async def check_database():
await db.execute('SELECT 1')
return 'Database connection OK'
def check_cache():
return 'Cache OK' if redis.ping() else 'Cache failed'
health_checker.register('database', check_database)
health_checker.register('cache', check_cache)
@app.get('/health')
async def health():
results = await health_checker.check_all()
# Если хотя бы один failed — возвращаем 503
all_ok = all(r['status'] == 'ok' for r in results.values())
status_code = 200 if all_ok else 503
return results, status_code
# LoadBalancer/Kubernetes используют /health для
# определения, жив ли сервис
9. SLA и SLO мониторинг
# SLA (Service Level Agreement) — договор
# SLO (Service Level Objective) — цель
class SLOMonitor:
def __init__(self):
self.metrics = {
'availability': 0.999, # 99.9% uptime
'latency_p99': 0.5, # p99 < 500ms
'error_rate': 0.001, # < 0.1% errors
}
def check_slo(self):
"""Проверяет, выполняются ли SLO"""
current_availability = self._get_availability()
current_latency = self._get_latency_p99()
current_error_rate = self._get_error_rate()
status = {
'availability': {
'target': f"{self.metrics['availability']:.1%}",
'current': f"{current_availability:.1%}",
'ok': current_availability >= self.metrics['availability']
},
'latency_p99': {
'target': f"{self.metrics['latency_p99']}s",
'current': f"{current_latency:.3f}s",
'ok': current_latency <= self.metrics['latency_p99']
},
'error_rate': {
'target': f"{self.metrics['error_rate']:.2%}",
'current': f"{current_error_rate:.2%}",
'ok': current_error_rate <= self.metrics['error_rate']
}
}
return status
def _get_availability(self):
# Запрашиваем из Prometheus
pass
def _get_latency_p99(self):
pass
def _get_error_rate(self):
pass
10. Мой стандартный стэк мониторинга
"""
Проduction Monitoring Stack:
┌─────────────────────────────────────────────┐
│ Application Code │
├─────────────────────────────────────────────┤
│ Logging (Python logging + structlog) │ → Логи
│ Metrics (prometheus_client) │ → Метрики
│ Tracing (OpenTelemetry) │ → Трассировка
├─────────────────────────────────────────────┤
│ Filebeat/Fluentd (агент сбора) │
├─────────────────────────────────────────────┤
│ ELK Stack: │
│ - Elasticsearch (хранилище логов) │
│ - Logstash (обработка логов) │
│ - Kibana (визуализация логов) │
├─────────────────────────────────────────────┤
│ Prometheus (временные ряды метрик) │
│ Grafana (дашборды) │
│ AlertManager (алертинг) │
├─────────────────────────────────────────────┤
│ Jaeger (дистрибьютированная трассировка) │
├─────────────────────────────────────────────┤
│ PagerDuty/Slack (уведомления) │
└─────────────────────────────────────────────┘
"""
11. Мой Чеклист Мониторинга
"""
Перед production deploym проверяю:
[ ] Все критичные ошибки логируются
[ ] Есть health check endpoints
[ ] Метрики для основных операций
[ ] Алерты настроены для:
[ ] Database availability
[ ] High error rate (>5%)
[ ] High latency (p99 > 1s)
[ ] High CPU/Memory usage
[ ] Disk space low (<10% free)
[ ] Логи структурированы (JSON)
[ ] Request ID для трассировки
[ ] Dashboard создан
[ ] Runbook для типичных инцидентов
[ ] SLO определены и мониторятся
[ ] Retention политика для логов (30 дней)
[ ] Backup планы
"""
Заключение
Мониторинг production систем — это целая наука. Основные принципы:
- Three Pillars: Logs, Metrics, Traces
- RED метрики: Rate, Errors, Duration
- Структурированное логирование: JSON с контекстом
- Проактивные алерты: До того как пользователи заметят
- Dashboards: Видимость системы в реальном времени
- SLO мониторинг: Гарантируем качество сервиса
- Automation: Alerting → Slack → PagerDuty → Engineer
Без мониторинга невозможно надежно 運運ать production систему.