Это восьмая статья серии «Эксплуатация VPS / DevOps-база». К концу прошлого шага (Обновления без простоя) машина актуальна: security-патчи ставятся, вы видите «патч применён?» через reboot-required/needrestart, PHP обновляется почти незаметно, есть путь отката. Но «обновляю вовремя» не отвечает на главный вопрос: а всё ли в порядке прямо сейчас? Сервер может быть полностью в актуальном состоянии и при этом лежать — потому что кончился диск, потому что OOM-killer сожрал MariaDB, потому что какой-то cron раздулся в бесконечный цикл и съел всю RAM. Вы об этом узнаете не из apt, а из того, что сайт перестал открываться.
В серии про архитектуру мы строили мониторинг приложения: метрики запросов, latency, SLO, трейсы. Здесь — про машину: какие пять цифр реально спасают самописный VPS, как за ними следить без enterprise-тяжести (node_exporter + Prometheus — или лёгкий cron-скрипт, если вы один и сайтов немного), как настроить logrotate, чтобы логи (включая slowlog PHP-FPM из Части VI) не съели диск, и как построить алерты так, чтобы они будили вас по делу, а не учили игнорировать уведомления («alert fatigue» — привычка не замечать алерты, потому что их слишком много).
Термины, которые введём один раз: метрика — число, которое замеряют во времени (сколько памяти занято, сколько запросов в секунду); дашборд — экран с графиками метрик; алерт — правило «если метрика пересекла порог — сообщить»; порог (threshold) — число, на котором алерт срабатывает. load average — «средняя длина очереди» процессов, которые хотят на CPU (внимание: на Linux учитывает и ждущих диск, см. Часть I). iowait — доля времени CPU, проведённая в ожидании диска (высокая = диск тормоз, не процессор). inode — запись в файловой системе, описывающая один файл; места на диске может быть полно, а иноды закончились → «No space left on device» при видимых гигабайтах свободно. node_exporter — крошечная программа, которая отдаёт метрики машины (CPU/RAM/диск) по HTTP в формате Prometheus. Prometheus — база time-series метрик (метрики с временны́ми метками) + движок алертов, которая «собирает» node_exporter. SLO/SLI (Service Level Objective / Indicator) — из серии архитектура: измеримая цель надёжности («99,5% времени сайт отвечает < 1 с»); здесь мы связываем машинные пороги с этой целью. Все домены/IP условные; подставляйте свои.
Часть I. Пять метрик, которые реально спасают, и как их читать
Прежде чем что-то строить, поймите, что именно спасает жизнь на одном VPS. Десяток «полезных» цифр на практике сводится к пяти вопросам. На каждый — команда, которая отвечает за секунды.
1. Загрузка: load average — очередь, а не проценты
uptime
# ... load average: 0.18, 0.21, 0.15
# три числа: среднее за 1/5/15 минут
nproc # сколько у вас ядер CPU
Как читать: load average — это сколько работы «хочет» выполниться. Ориентир — сравните с числом ядер (nproc). На машине с 2 ядрами load 2.0 = ядра забиты под завязку; load 4.0 на 2 ядрах = очередь, запросы ждут.
⚠️ Главная ловушка load average. На Linux в load попадают и процессы, ждущие диск (
iowait), а не только CPU. Поэтому высокий load при пустом CPU почти всегда означает «тормозит диск» (или база), а не «не хватает процессора». Смотрите связку:load↑ +%usrв норме +%wa↑ = диск-проблема. Разложим в пункте 3.
2. Память: смотри Available, не free
free -h
# total used free buff/cache available
# Mem: 1.9Gi 1.3Gi 80Mi 500Mi 540Mi
Как читать: available — сколько памяти реально можно отдать новому процессу (ядро умеет быстро отдать buff/cache под новые нужды). Колонка free (80 Mi) — это «просто не занята прямо сейчас», она на живой машине почти всегда маленькая, и пугаться «free мало» — ошибка. Смотрите available; если он падает к нулю — следующий шаг OOM-killer (см. Часть V про swap как подстраховку и финальную статью про диагностику).
Память «утекает» проверяется историей: free -h раз в час через cron-лог (Часть II) покажет монотонно растущий used — признак утечки (и отсюда же берёт смысл pm.max_requests из Части II — пересоздавать воркеров, не давая утечке накопиться).
3. Диск по времени отклика: iowait
# vmstat 1 3 — среднее за 3 секунды
vmstat 1 3
# ... r b swpd free ... us sy id wa
# ... 2 ... 5 2 5 88 ← wa=88% это очень плохо
Как читать: колонка wa (iowait) — сколько времени CPU простаивал, ждя диск. Здоровая NVMe-машина на WordPress: wa в единицы процентов. Если wa стабильно высокий (20–50%+) — диск не успевает: вероятные причины — не хватает innodb_buffer_pool_size (база свопит страницы с диска, см. Часть III), кончился кэш, «кто-то» пишет большие файлы, или диск/сетап медленный (дёшевый HDD-backed VPS). Это опережающий сигнал «через минуту будет load average ↑ и сайт затормозит».
4. Диск по месту и по инодам: df -h и df -i
df -h / # место: Filesystem Size Used Avail Use% Mounted
df -i / # иноды: тот же взгляд, но по «числу файлов»
# где жрут:
sudo du -xh --max-depth=1 / 2>/dev/null | sort -h | tail -n 15
Как читать: df -h — привычка «диск заполнен на 91%» → почти неизбежно кончится (логи, tmp, бэкапы). Но df -h может показать 50% свободно при закончившихся инодах — тогда создание любого файла падает с No space left on device. Это классика «свалки из миллиона крошечных файлов» (сессии PHP в /var/lib/php/sessions, кэш-фрагменты, раздутые логи в тысячи мелких ротаций). Отсюда обязательный второй взгляд — df -i (IUse% ≈ 100% = закончились иноды). Профилактика обоих — logrotate (Часть III) и чистка.
5. Соединения и «что упало/перезапустилось»
# сколько открытых соединений по состояниям
ss -s
# соединения к базе и к 443
ss -tan state established | awk '{print $4}' | cut -d: -f1 | sort | uniq -c | sort -rn | head
# кто из юнитов systemd падал/перезапускался
systemctl --failed --no-pager
journalctl -u nginx -u php8.2-fpm -u mariadb -p err --since "1 hour ago" --no-pager | tail -n 30
Как читать: «слишком много соединений» (Too many connections, из Части VI) видно здесь по раздутому числу established к 3306. А рестарт-шторм юнита («PHP-FPM перезапустился 8 раз за минуту») виден по systemctl status (N restarts в юните) и по journalctl (цепочка Started/Stopped). Это прямая связь с тем, как вы уже читаете systemd-логи из Части V. Когда строк в журнале много и их надо фильтровать по содержимому — помогает journalctl -p err | grep -E и умение собрать нужный паттерн; regex для этого — в Регулярные выражения на практике.
6. «Одна команда на всё» — быстрый снэпшот
Когда вас разбудили «что-то не так», за 10 секунд прочитайте пять цифр разом:
echo "== load ==" && uptime
echo "== mem ==" && free -h | awk '/^Mem/{print $2,$3,$6,$7}'
echo "== disk ==" && df -h / | tail -1 && df -i / | tail -1
echo "== iowait ==" && vmstat 1 2 | tail -1 | awk '{print "wa="$NF}'
echo "== units failing ==" && systemctl --failed --no-legend | head
Этот набор — то, что в Часть II вы будете гонять по cron и шить в алерт: не «сорок метрик», а пять сигналов, которые спасают.
Чек-лист части
- Паникуют при малом `free` в `free -h`, не глядя на `available` — это нормальное состояние живой Linux (память занята кэшем).
- Видят высокий `load average` и сразу «не хватает CPU» → а по факту высокий `wa` = тормозит диск/база.
- Смотрят `df -h`, не смотрят `df -i` → однажды `No space left on device` при 30% занятого диска (кончились иноды).
- Не проверяют `systemctl —failed` после обновлений (из [статьи 7](obnovleniya-bez-prostoya-i-neobsluzhivaemye-patchi.md)) → упавший юнит тихо «не работает», а мониторинг приложений молчит.
Часть II. Два уровня стека: cron-скрипт против node_exporter + Prometheus
Минимальный стек на одной машине выбирают по числу сайтов/машин и по тому, нужны ли графики. Начинать с Grafana/облачных APM — оверинжиниринг для VPS на 2 ГБ RAM (сам стек мониторинга съест память, которую вы мониторите).
Уровень «достаточно»: cron-скрипт + алерт
Самая дешёвая рабочая схема: раз в N минут гонять чек из Части I, сравнивать с порогами, при пересечении — слать уведомление; плюс писать строку-снимок в лог, чтобы видеть историю.
#!/usr/bin/env bash
# /usr/local/bin/os-check.sh — минимальный watchdog одной машины
set -euo pipefail
THRESH_DISK=85 # % занятого диска
THRESH_INODE=85
THRESH_MEM_AVAIL_PCT=10 # available < 10% от total → тревога
THRESH_LOAD_PER_CPU=2.0 # load1 > ядра*2 → тревога
LOG=/var/log/os-check.log
load1=$(awk '{print $1}' /proc/loadavg)
nproc=$(nproc)
disk=$(df -P / | awk 'NR==2{gsub("%","",$5);print $5}')
inode=$(df -Pi / | awk 'NR==2{gsub("%","",$5);print $5}')
mem_avail=$(awk '/MemAvailable/{print $2}' /proc/meminfo)
mem_total=$(awk '/MemTotal/{print $2}' /proc/meminfo)
mem_pct=$(( mem_avail * 100 / mem_total ))
load_limit=$(awk -v n="$nproc" -v m="$THRESH_LOAD_PER_CPU" 'BEGIN{print n*m}')
ts=$(date -u +%FT%TZ)
echo "$ts load=$load1/$nproc disk=$disk% inode=$inode% mem_avail=$mem_pct%" >> "$LOG"
fail=""
[ "$disk" -ge "$THRESH_DISK" ] && fail="$fail disk:${disk}%"
[ "$inode" -ge "$THRESH_INODE" ] && fail="$fail inode:${inode}%"
[ "$mem_pct" -lt "$THRESH_MEM_AVAIL_PCT" ] && fail="$fail memavail:${mem_pct}%"
awk -v l="$load1" -v m="$load_limit" 'BEGIN{exit !(l>m)}' && fail="$fail load:${load1}"
if [ -n "$fail" ]; then
# канал алерта — см. Часть IV (webhook/email). Здесь заглушка:
echo "ALERT host=$(hostname) -$fail" >&2
fi
Подвешиваем на cron (механика планировки — та же, что в Части IV про warm-up и в бэкапах из Части IV):
# /etc/cron.d/os-check — каждые 5 минут
*/5 * * * * root /usr/local/bin/os-check.sh >/dev/null 2>&1
Плюсы: ноль памяти на сам монитор, всё видно через tail /var/log/os-check.log, легко читать/править, нет внешних зависимостей. Минусы: нет графиков, порог «в лоб» (не видно тренда), каждый чек — это отдельный запуск. Для одной машины этого часто достаточно, а os-check.log потом легко скормить в Prometheus через textfile-collector, если решите расти.
Уровень «растём»: node_exporter + Prometheus
Когда хочется графики, тренды и алерты по истории (или машин/сайтов стало несколько) — стандартный лёгкий стек:
node_exporter (на вашей машине, метрики ОС) ──┐
├── Prometheus (сбор + алерты) ── Alertmanager / уведомление
node_exporter (другие машины) ────────────────┘
- node_exporter — один бинарь, слушает
:9100, отдаёт/metrics(CPU, RAM, диск, сеть, иноды, …). Ставится на каждую машину. - Prometheus — раз в
scrape_interval(например, 15s) «скрейпит»/metrics, хранит ряды, умеет язык запросов PromQL и алерты.
# node_exporter через apt (Ubuntu/Debian) или бинарем
sudo apt install -y prometheus-node-exporter
sudo systemctl status prometheus-node-exporter --no-pager | head -n 5
curl -s http://127.0.0.1:9100/metrics | head # сырые метрики
Примеры PromQL под пять метрик Части I:
# свободная память, доля
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes
# занято диска на "/" (срабатывает и на иноды отдельно: node_filesystem_inodes_free / _total)
1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})
# load1 на ядро
node_load1 / count(node_cpu_seconds_total{mode="idle"}) without cpu
# iowait: доля idle-времени, ушедшая в ожидание диска, за 5 минут
rate(node_cpu_seconds_total{mode="iowait"}[5m])
Где ставить Prometheus: на другую машину или VPS-контейнер, а не на ту же, что вы мониторите, — иначе при полном падении вашей машины алерт тоже умрёт (это ровно та причина, по которой нужен heartbeat из Части IV). Если Prometheus на той же машине — закройте ему порт :9090 наружу firewall-ом (Часть II: bind 127.0.0.1 или allow только под ваш IP), иначе дашборд метрик торчит в интернет.
Честная граница: node_exporter + Prometheus «закрыли машину». Для прикладных метрик (latency сайта, ошибки PHP, «не открывается страница») нужен либо blackbox-пробник (Prometheus
blackbox_exporter: ходит по HTTPS и меряет код/время), либо отдельный uptime-сервис (Часть IV). Разделение «OS-метрики vs app-метрики» — та же мысль, что в Метрики и мониторинг: машина и приложение падают независимо.
Чек-лист части
- Ставят Prometheus+Grafana+Alertmanager «сразу как в докладе» на VPS 2 ГБ, где мониторинг жрёт 40% RAM, нужной сайту. Для одной машины — cron-скрипт.
- node_exporter/Prometheus торчит наружу (`:9100`/`:9090` открыты миру) → утечка метрик, а `:9100` без firewall — ещё и вектор. Закрывать так же, как в [Части II](firewall-i-ssh-hardning-zakryvaem-perimetr-mashiny.md).
- Prometheus на той же машине, что мониторит → «монитор умер вместе с сервером, и алерта не было».
- Метрики ОС есть, а ответа на «открывается ли сайт» нет → не хватает blackbox/uptime-пробы (Часть IV).
Часть III. logrotate: чтобы логи и slowlog не съели диск
Прямая линия к самому частому способу «уронить» живой VPS: диск кончился от логов. У вас теперь логов больше, чем было в начале серии: nginx access/error (из Части III), PHP-FPM slowlog (из Части VI), MariaDB error-лог и slow-лог, journal systemd (из Части V), бэкапы mysqldump (из Части IV). Ни один из них не сжимается и не удаляется сам — всем управляет logrotate.
1. Что делает logrotate и почему без него кончается диск
logrotate запускается по cron/systemd-таймеру (обычно ежедневно) и для каждого файла, перечисленного в /etc/logrotate.d/, применяет правило: «раз в срок или по достижении размера переименовать текущий лог (app.log → app.log.1), сжать, удалить самые старые (держать N штук)». Без него access.log на оживлённом сайте наедает гигабайты за неделю.
Две независимые ловушки диска:
df -h(закончились байты — раздутые логи/бэкапы) иdf -i(закончились иноды — свалка из миллионов мелких файлов: раздутая/var/lib/php/sessions, тысячи сжатых ротаций). Иноды не лечатсяlogrotate, лечатся чисткой и (для сессий)systemd-tmpfiles/своимsession.save_pathна tmpfs (см. Часть III про пулы).
2. Конфиг и разбор ключевых директив
Свой файл в /etc/logrotate.d/nginx-wordpress (override-принцип, как везде в серии — не правим чужие дефолты):
/var/log/nginx/*.log /var/www/example.test/wp-content/debug.log {
daily # или size 50M — ротируем и по размеру тоже
rotate 14 # держать 14 старых копий, дальше удалять
compress # gzip старых (.1 → .1.gz)
delaycompress # не сжимать самый свежий поворот (демон ещё может дописывать)
missingok # файла нет — не ошибка, молча пропускаем
notifempty # пустой файл не ротируем
create 0640 www-data adm # после ротации создать новый лог с нужными правами/владельцем
sharedscripts # postrotate-скрипт один раз на весь блок, а не на каждый файл
postrotate
# сказать демону «закрой старый дескриптор и пиши в новый» — КРИТИЧНО
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid) 2>/dev/null || true
endscript
}
Ключевые директивы и зачем:
dailyvssize 50M—dailyротит по календарю;size 50M— как только превышен размер (полезно для «взрывных» access-логов). Можно совмещать сmaxsize(«daily, но если больше 50M — хоть сейчас»).rotate N— глубина хранения:14= ~2 недели. Это и ваш «бюджет места на логи»; на 16 ГБ диске не стоит держатьrotate 365.compress+delaycompress— gzip экономит 80–95% места;delaycompressнужен, потому что демон ещё держит открытый старый файл — жать его «на лету» нельзя, ждём один цикл.create … owner group— без этого после ротации новый лог может создаться с правами logrotate (root), и демон его не запишет → «логи пропали» (тихий отказ писать).sharedscripts+postrotate— самое важное и самое пропускаемое.
3. Почему без postrotate лог «зависает в старом файле»
Лог — это открытый файловый дескриптор демона. logrotate переименовывает error.log → error.log.1, создаёт новый пустой error.log, но демон (nginx/php-fpm) держит дескриптор старого inode и продолжает писать в error.log.1. Пока вы не дадите сигнал, новый файл останется пустым, а место жрёт «ротированный». Отсюда — postrotate:
- nginx — сигнал
USR1(kill -USR1): перечислить логи (не рвёт соединения, из механики reload Части III). - php-fpm — тоже
USR2/USR1(kill -USR2 $(cat /run/php/php8.2-fpm.pid)) илиsystemctl reload php8.2-fpm. - rsyslog (syslog-логи) — свой postrotate (
systemctl kill -s HUP rsyslog).
Отдельно journal (systemd) живёт не через logrotate, а сам по себе: ограничить через /etc/systemd/journald.conf → SystemMaxUse=200M и systemctl restart systemd-journald (иначе journal silently разрастается до ~10% раздела). Это тот же журнал, что читаете journalctl из Части V.
4. Проверка без ожидания «завтра cron сам»
# сухим ходом: что logrotate СДЕЛАЕТ и где ошибки синтаксиса конфига
sudo logrotate -d /etc/logrotate.conf
# реально прогнать один блок (тестово «забить» и проверить, что демон принял сигнал)
sudo logrotate -f /etc/logrotate.d/nginx-wordpress
# после — убедиться, что .1 появился, новый пишется, права верные
ls -l /var/log/nginx/ | head
Чек-лист части
- Забыли `postrotate`/`kill -USR1` → после ротации nginx пишет в старый `.1`, новый `error.log` пуст, а диск кончается «из-под одного файла».
- `rotate 365` на маленьком диске → логи сожрали место; ставьте глубину по бюджету диска.
- Нет лимита journal (`SystemMaxUse`) → `/var/log/journal` тихо наелает гигабайты, logrotate его не чистит.
- Не проверяют `df -i`/не чистят сессии → иноды кончились при 30% занятого места.
- Не делают `logrotate -d` перед `deploy` конфига → синтаксическая ошибка в `.d/` ломает ротацию всех логов сразу.
Часть IV. Алерты: threshold и heartbeat — чтобы монитор не был «слепым»
Метрики в дашборде бесполезны, пока вы на них не смотрите. Чтобы вас будило само, нужны алерты — двух типов, и второй важнее.
1. Type-1: пороговый алерт (threshold)
«Метрика пересекла границу → сообщение». На cron-скрипте — это if fail → послать; на Prometheus — правило в *.rules.yml:
# alert-rules.yml — фрагмент
- alert: DiskAlmostFull
expr: 1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) > 0.85
for: 10m # «для:10m» — алерт горит только если держится 10 минут (гистерезис, против дёрганья)
annotations:
summary: "{{ $labels.instance }}: диск > 85% 10 минут"
Ключевое — for (гистерезис). Без него алерт орёт на каждое кратковременное касание порога (диск подскочил до 86% на минуту при mysqldump — и вас разбудили). for: 10m значит «только если держится».
2. Type-2: heartbeat / dead man’s switch — ловит «монитор умер»
Пороговый алерт немой, когда монитор упал (упал node_exporter, упал Prometheus, кончился cron, упала сама машина — алерта нет, и вы думаете «всё ок»). Лечится dead man’s switch («курок мёртвого человека», из сигнальных систем): не «сообщи, если плохо», а наоборот — «сообщи, если НЕ прилетел сигнал что всё хорошо».
Механика: машина регулярно «пинкует» внешний приёмник («я жив»); приёмник алертует, если пинга нет в окне.
# в тот же cron (каждые 5 мин) — сообщить внешнему health-эндпоинту «я жив»
curl -sf --max-time 8 https://hc-ping.com/Ваш-токен >/dev/null || true
Приёмник (healthchecks.io, «ping» от своего же мониторинга, Telegram-бот на чужом хосте) алертует, если >15 мин тишины. Важное следствие: приёмник обязан жить на другой машине, иначе при падении VPS умрёт и он. Это ответ на «Prometheus на той же машине» из Части II.
Heartbeat ловит «упало всё, включая мониторинг»; threshold ловит «монитор жив, но метрика плохая». Нужны оба — иначе слепые зоны.
3. Канал доставки: email или webhook
- Email — простой и «в карман». Отправка с машины — через лёгкий MTA (
msmtp/ssmtpк вашему SMTP), потому что на чистом VPS нетsendmail(настроить полноценный почтовый сервер Postfix/Dovecot — отдельная тема вне этой серии). Alertmanager имеетemail_configиз коробки. - Webhook (Telegram-бот, Slack, healthchecks) — быстрее и «в телефон»; Alertmanager отдаёт POST сам. Про «фоновые процессы и приёмники» — перекликается с Сервис-воркеры и офлайн-режим.
Канал алерта не должен зависеть от того же, что алертует (алерт «база легла», который шлёт сама база через SMTP на том же хосте = алерт, который не уйдёт при падении). heartbeat + приёмник на стороне — это страховка и от «SMTP-тупик».
4. Alert fatigue — почему «орать на всё» хуже молчания
Если алерт срабатывает по пустякам, вы начинаете его игнорировать, и однажды игнорируете настоящий. Правила «не орём в пустоту»:
- Пороги ставьте на реальную границу боли, а не «1% отклонения» (CPU 95% на 20 секунд не будит; диск 90% на 30 минут — будит).
for-гистерезис везде (часть 1).- Разделяйте critical (буди немедленно: диск кончился, сайт не отвечает) и warning (посмотри днём: диск 75%, патч не применён, load слегка выше нормы). Будить ночью — только critical.
- Каждый алерт — с действием. «Диск > 85%» → «удалить старые бэкапы / почистить логи (Часть III)». Если к алерту нет первого действия — он информационный шум, понижайте его до warning/дашборда.
Чек-лист части
- Только threshold, без heartbeat → «монитор лёг вместе с сервером», алертов нет, узнали от пользователя через сутки.
- Heartbeat-приёмник на том же VPS → не спасает при падении машины (смысл потерян).
- Алерты без `for` → ложные срабатывания на касание порога, вы привыкли их закрывать.
- Всё помечено critical → «мальчик, который кричал волк», настоящий инцидент утонул в шуме.
- Алерт «SMTP с той же машины» и база упала/почта не уходит → уведомление не доставлено.
Часть V. Пороги и SLO: машинный алерт как опережающий индикатор
Финальный скрепляющий смысл: зачем пороги именно такие. В серии про архитектуру вы задали SLO («99,5% времени страница отвечает < 1 с», error-budget). Машинный мониторинг — не про «посмотреть красивые цифры», а про то, чтобы upstream-метрика упала раньше, чем это почувствует SLO. Установите связь «машинный порог → какая SLO-граница за ним».
1. Цепочка: машина → приложение → пользователь
диск/иноды → RAM/available → iowait → load → [PHP-FPM 502, slow запросы] → [latency/ошибки сайта] → SLO
Машинный алерт — первый в цепочке: он бьёт до того, как пользователь заметил. Примеры связей (пороги условные, калибруйте под свою машину):
| Машинная метрика | Что за ней следует для приложения | Смысл порога |
|---|---|---|
df / > 85% (warn) / > 92% (crit) | через часы/дни кончится → БД не пишет, сессии падают, wp-admin не работает | warn даёт вам сутки на расчистку логов (Часть III) |
df -i > 90% | создание любого файла падает → запись сессий/кэша/дампа | крит, будит: «иноды» — это внезапный отказ «без нехватки байт» |
available < 10% | следующий спайк → OOM-killer съест MariaDB/PHP-FPM (Часть V) | warn заранее, пока swap ещё держит |
iowait стабильно > 20% | база свопит страницы, latency сайта ползёт вверх → ближе к SLO-нарушению | предупреждает «диск-узкое место», чинят innodb_buffer_pool (Часть III) |
load1 > ядра×2 на 10м | очередь, воркеры PHP ждут CPU → 502/таймауты | крит, будит: это уже «тормозим для пользователя» |
юнит в --failed / рестарт-шторм | сервис лежит/перезапускается (Часть II) | крит, будит: сайт может быть уже недоступен |
Заметьте: пороги не «из воздуха» — каждый привязан к тому, как это ударит по SLO и что делать (чистить логи, добавить swap, поднять buffer pool, снять зависший коннект из Части VI). Это и есть отличие зрелого мониторинга от «орём на всё».
2. Что алертить, а что — нет (граница «машина vs приложение»)
Эта статья держит машину (CPU/RAM/диск/иноды/юниты/iowait). Приложение (латентность, ошибки PHP, «главная не отдаётся», битые страницы) — это Метрики и мониторинг из архитектуры плюс blackbox-проба («раз в минуту GET https://example.test, ждём 200 и время < X») и uptime-алерт (Часть IV heartbeat). Не дублируйте: машинный алерт не должен дублировать app-алерт, но должен быть раньше него по времени. Правильная картина при деградации: сначала молча горит warn «available падает», крит «iowait 30%», и только потом app-алерт «latency P95 > 2s» и «SLO burning». Если вы увидели первым app-алерт, а машинных warn не было — пороги Части I–V надо пересмотреть.
3. Минимальный «аварийный» набор для одной машины (сборка воедино)
Если вы всё-таки один и не хотите ни Prometheus, ни Grafana, вот рабочий floor из трёх кусков (собирается из Частей I–IV):
os-check.sh(Часть II) — порога по 5 метрикам,log-история + крит-вывод.- в него же — heartbeat
curl hc-ping(Часть IV), приёмник на другом хосте. logrotate.d/nginx-wordpress+ лимит journal (Часть III) — чтобы диск не кончился сам по себе, плюс blackbox-проба «главная = 200» (из app-слоя).
Этого хватает, чтобы не узнать о падении от пользователя. Всё остальное (графики, тренды, P95-дэшборды) — приятный рост, когда машины/сайты стали числами.
Чек-лист части
- Пороги скопированы «с чужого VPS на 32 ГБ» без привязки к своему дисковому/памятному бюджету → молчат вхолостую или орут без причины.
- Нет warn, только crit → узнаёте о проблеме ровно в момент падения (сутки запаса на действия потеряны).
- Машинные алерты дублируют app-алерты (оба «сайт лежит») → шум; машинный должен быть раньше.
- Алерт без «первого действия» → реакция каждый раз с нуля и в панике; к каждому криту держите ссылку на чек-лист.
Инструмент под задачу
Опросник метрик и алерт-скрипты живут по расписанию: соберите корректный crontab (частота, ловля вывода, ротация), не путая минуты и PATH. Попробуйте инструмент прямо здесь, на своих данных:
Чек-лист граблей всей статьи
- Смотрят `free`, не `available` → паника на здоровой машине, занявшей память кэшем.
- `load average` высокий → автоматически «не хватает CPU»; а на деле высокий `wa` = диск/база.
- Смотрят только `df -h`, не `df -i` → `No space left on device` при 30% занятого места (иноды).
- Нет `logrotate`/лимита journal → логи медленнно, верно съедают диск, однажды — «сайт лежит из-за места».
- `logrotate` без `postrotate` (`kill -USR1` nginx / reload php-fpm) → новый лог пуст, демон пишет в ротированный `.1`.
- Только threshold, без heartbeat → «монитор умер вместе с сервером», алертов нет.
- Heartbeat-приёмник/Prometheus на том же VPS, что мониторит → не спасает при падении.
- Пороги без `for`-гистерезиса и всё помечено critical → alert fatigue, настоящий инцидент проигнорирован.
- Пороги «из воздуха», не привязаны к «что ударит по SLO и что делать» → к алерту нет реакции.
- Алерт шлёт SMTP с той же машины, что упала → уведомление не уходит.
Материал написан простым языком; любой англоязычный термин (метрика, дашборд, алерт, threshold, load average, iowait, inode, swap, OOM-killer, node_exporter, Prometheus, PromQL, time-series, scrape, Alertmanager, heartbeat/dead man’s switch, alert fatigue, hysteresis/
for, logrotate, journal/journald, SLO/SLI, blackbox-probe) объясняется при первом употреблении. Конфиги — для Ubuntu/Debian; имена пакетов/юнитов (prometheus-node-exporter/node_exporter,php8.2-fpm/8.3, пути логов,nproc), поведение postinstaptи наличиеmsmtp/SMTP сознательно условны — проверяйте фактические черезsystemctl status,logrotate -d,df. Домены/IP/номера портов/пороги условные (example.test,203.0.113.x— TEST-NET как в №1,85%/20%/10m— ориентиры, калибруйте под свой бюджет диска/RAM). Правило серии действует: приёмник алертов и сам монитор — не на той же машине, что вы сторожите; порог с привязкой к действию, а будит ночью только critical. Тонкие механизмы (log-based метрики через Loki, трейсинг, distributed-мониторинг на флот, auto-healing, P95-дашборды Grafana) упомянуты лишь где нужно — это следующий уровень или отдельная разовая тема, когда базовый контур «пять метрик + logrotate + порог и heartbeat» уже стоит на машине и не даёт узнать о падении от пользователя.
👤 Зарегистрируйтесь, чтобы добавить материал в закладки.
