Настройка алертов по метрикам базы данных (CPU, память, диск, подключения)
Алерт — это уведомление, которое приходит до того, как пользователи заметили проблему. Алерт «диск заполнен на 95%» — это авария. Алерт «диск заполнен на 75%, рост 2 GB/сутки» — это 10 дней на решение проблемы. Правильные пороги и правильные каналы доставки — половина работы.
Стек мониторинга
Стандартный стек для баз данных:
PostgreSQL/MySQL/MongoDB
│
Exporter (postgres_exporter / mysqld_exporter / mongodb_exporter)
│ метрики в Prometheus формате
Prometheus (сбор и хранение метрик)
│
Alertmanager (маршрутизация алертов)
│
Telegram / Slack / PagerDuty
│
Grafana (визуализация)
Установка exporters
# PostgreSQL
docker run -d \
--name postgres_exporter \
-e DATA_SOURCE_NAME="postgresql://monitoring:password@localhost:5432/postgres?sslmode=disable" \
-p 9187:9187 \
quay.io/prometheuscommunity/postgres-exporter:latest
# MySQL
docker run -d \
--name mysqld_exporter \
-e DATA_SOURCE_NAME="monitoring:password@(localhost:3306)/" \
-p 9104:9104 \
prom/mysqld-exporter:latest
# Node Exporter для системных метрик (CPU, RAM, disk)
docker run -d \
--name node_exporter \
--pid="host" \
-v /:/host:ro,rslave \
-p 9100:9100 \
quay.io/prometheus/node-exporter:latest \
--path.rootfs=/host
Пользователь для мониторинга PostgreSQL (минимальные права):
CREATE USER monitoring WITH PASSWORD 'monitoring_password';
GRANT pg_monitor TO monitoring; -- системная роль PG 10+
-- или вручную:
GRANT SELECT ON pg_stat_database TO monitoring;
GRANT SELECT ON pg_stat_replication TO monitoring;
GRANT EXECUTE ON FUNCTION pg_current_wal_lsn() TO monitoring;
Правила алертов Prometheus
# /etc/prometheus/rules/database.yml
groups:
- name: postgresql_critical
rules:
# Недоступность базы
- alert: PostgreSQLDown
expr: pg_up == 0
for: 30s
labels:
severity: critical
annotations:
summary: "PostgreSQL недоступен на {{ $labels.instance }}"
description: "База данных не отвечает более 30 секунд"
# Диск заполнен > 85%
- alert: DiskSpaceHigh
expr: |
(node_filesystem_size_bytes{mountpoint="/var/lib/postgresql"} -
node_filesystem_free_bytes{mountpoint="/var/lib/postgresql"}) /
node_filesystem_size_bytes{mountpoint="/var/lib/postgresql"} * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "Диск PostgreSQL заполнен на {{ $value | printf \"%.1f\" }}%"
# Критическое заполнение диска
- alert: DiskSpaceCritical
expr: |
(node_filesystem_size_bytes{mountpoint="/var/lib/postgresql"} -
node_filesystem_free_bytes{mountpoint="/var/lib/postgresql"}) /
node_filesystem_size_bytes{mountpoint="/var/lib/postgresql"} * 100 > 95
for: 1m
labels:
severity: critical
annotations:
summary: "КРИТИЧНО: диск PostgreSQL заполнен на {{ $value | printf \"%.1f\" }}%"
# Много соединений
- alert: PostgreSQLTooManyConnections
expr: |
pg_stat_activity_count / pg_settings_max_connections * 100 > 80
for: 2m
labels:
severity: warning
annotations:
summary: "Использовано {{ $value | printf \"%.0f\" }}% соединений PostgreSQL"
description: "Рассмотрите PgBouncer или увеличение max_connections"
# Долгие транзакции (> 10 минут)
- alert: PostgreSQLLongRunningTransaction
expr: |
pg_stat_activity_max_tx_duration{state="active"} > 600
for: 1m
labels:
severity: warning
annotations:
summary: "Транзакция выполняется {{ $value | printf \"%.0f\" }} секунд"
# Лаг репликации > 60 секунд
- alert: PostgreSQLReplicationLag
expr: pg_replication_lag > 60
for: 2m
labels:
severity: critical
annotations:
summary: "Реплика отстаёт на {{ $value | printf \"%.0f\" }} секунд"
- name: postgresql_warning
rules:
# Cache hit rate < 99%
- alert: PostgreSQLLowCacheHitRate
expr: |
(sum(pg_stat_database_blks_hit) /
(sum(pg_stat_database_blks_hit) + sum(pg_stat_database_blks_read))) * 100 < 99
for: 10m
labels:
severity: warning
annotations:
summary: "Cache hit rate: {{ $value | printf \"%.1f\" }}% (норма > 99%)"
# CPU > 80%
- alert: HighCPUUsage
expr: |
100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
annotations:
summary: "CPU {{ $labels.instance }}: {{ $value | printf \"%.0f\" }}%"
# RAM < 10% свободно
- alert: LowFreeMemory
expr: |
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10
for: 5m
labels:
severity: warning
annotations:
summary: "Свободной памяти: {{ $value | printf \"%.1f\" }}%"
Alertmanager: маршрутизация в Telegram
# /etc/alertmanager/alertmanager.yml
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'instance']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: telegram-critical
routes:
- match:
severity: critical
receiver: telegram-critical
repeat_interval: 30m # критичные повторять каждые 30 минут
- match:
severity: warning
receiver: telegram-warning
repeat_interval: 4h
receivers:
- name: telegram-critical
telegram_configs:
- api_url: "https://api.telegram.org"
bot_token: "BOT_TOKEN"
chat_id: -1001234567890 # ID группы/канала
message: |
🔴 *{{ .GroupLabels.alertname }}*
{{ range .Alerts }}
*{{ .Annotations.summary }}*
{{ .Annotations.description }}
Время: {{ .StartsAt.Format "15:04:05" }}
{{ end }}
parse_mode: "Markdown"
- name: telegram-warning
telegram_configs:
- api_url: "https://api.telegram.org"
bot_token: "BOT_TOKEN"
chat_id: -1001234567891 # отдельный канал для warning
message: |
⚠️ *{{ .GroupLabels.alertname }}*
{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}
parse_mode: "Markdown"
MySQL-специфичные алерты
- name: mysql_alerts
rules:
- alert: MySQLDown
expr: mysql_up == 0
for: 30s
labels:
severity: critical
- alert: MySQLSlowQueries
expr: rate(mysql_global_status_slow_queries[5m]) > 5
for: 2m
labels:
severity: warning
annotations:
summary: "MySQL: {{ $value | printf \"%.1f\" }} медленных запросов/сек"
- alert: MySQLInnoDBBufferPoolHitRateLow
expr: |
(mysql_global_status_innodb_buffer_pool_read_requests -
mysql_global_status_innodb_buffer_pool_reads) /
mysql_global_status_innodb_buffer_pool_read_requests * 100 < 99
for: 10m
labels:
severity: warning
annotations:
summary: "InnoDB buffer pool hit rate: {{ $value | printf \"%.1f\" }}%"
- alert: MySQLReplicationLag
expr: mysql_slave_status_seconds_behind_master > 30
for: 1m
labels:
severity: critical
Прогнозирование исчерпания диска
Prometheus умеет предсказывать на основе тренда:
# Предсказание: диск закончится через < 3 дней
- alert: DiskWillFillSoon
expr: |
predict_linear(
node_filesystem_free_bytes{mountpoint="/var/lib/postgresql"}[6h],
3 * 24 * 3600
) < 0
for: 1h
labels:
severity: warning
annotations:
summary: "Диск PostgreSQL закончится менее чем через 3 дня по текущему тренду"
predict_linear использует линейную регрессию по последним 6 часам данных.
Проверка работы алертов
После настройки проверяем через Alertmanager UI (http://alertmanager:9093) и принудительно триггерим тестовый алерт:
curl -H "Content-Type: application/json" -d '[{
"labels": {"alertname": "TestAlert", "severity": "warning"},
"annotations": {"summary": "Test alert from setup verification"}
}]' http://localhost:9093/api/v1/alerts
Время настройки полного стека (exporter + Prometheus + Alertmanager + Telegram + Grafana): 4–8 часов для одной базы, день для комплексного мониторинга нескольких баз с дашбордами.







