Я держу небольшой парк Linux-серверов — bare metal, VPS, пара container-хостов — на которых тихо живут pet-проекты и пара платных продуктов. Ничего экзотичного, но реальные клиенты зависят от того, что всё работает.

Прод почти никогда не падает разом. Обычно он деградирует: сервис начинает свопиться под нагрузкой, память тихо подтекает по нескольку мегабайт в час, шумный сосед на общем диске превращает 5 мс чтение в 500. К моменту, когда алерт «сайт лежит» пришёл, вы уже не разбираете пожар — вы объясняете его клиентам.

Я держу Netdata на этих серверах несколько лет, и не один раз она ловила «медленное горение» до того, как оно становилось настоящим инцидентом. Эта статья — как я её использую: установка, дефолты, которые я меняю, parent–child для масштаба и три продакшен-истории, в которых Netdata спасла меня от простоя.

Что мы хотим от мониторинга

До инструмента — про цели. Мониторинг — это не красивые дашборды, это быстрые ответы на три вопроса:

  • Что изменилось? Когда сервер начал чудить в 02:14, что было иначе в 02:13?
  • Где узкое место? CPU, RAM, swap, диск, сеть, дескрипторы, конкретный процесс?
  • Как узнать раньше пользователей? На каком пороге нас должны были разбудить за 20 минут до факапа?

Конкретно, мне нужны метрики на:

  • CPU по ядрам, отдельно system / user / iowait.
  • Давление на память, swap-in / swap-out.
  • Диск: throughput, IOPS, длина очереди, ошибки.
  • Сеть: throughput, retransmits, packet drops.
  • Здоровье сервисов: nginx, Postgres, MySQL, Redis, Docker, systemd-юниты.
  • Алерты, которые реально будят, — а не 200 дашбордов, в которые я не захожу.

Почему именно Netdata

Есть хорошие причины выбрать Prometheus + Grafana — длинная ретенция, язык запросов, экосистема экспортёров. Я выбираю Netdata из-за другого набора компромиссов:

  • Установка одной командой. kickstart.sh — и через минуту агент уже собирает сотни метрик с разумными дефолтами, включёнными из коробки.
  • Маленький footprint. Типичный агент — меньше 2% CPU и 50–100 МБ RAM. Не нужно выделять серверы под мониторинг.
  • Per-second разрешение, в реальном времени. Большинство стеков агрегируют по 10–30 секундам. С 1-секундным разрешением 4-секундный спайк — это видимая засечка, а не призрак.
  • Auto-discovery. Поставил nginx, перезапустил Netdata — есть графики nginx. То же для Postgres, Redis, Docker, systemd. Никаких scrape config писать не надо.
  • Health-алерты из коробки. Сотни преднастроенных alarm’ов (swap, заполнение диска, ramping load) приезжают включёнными. Стартуете с разумных дефолтов, тюните дальше.

Я воспринимаю Netdata как day-1 инструмент: 80% видимости за 5% усилий. Если со временем понадобится длинная ретенция, custom-запросы или экзотические SLO — Netdata можно дополнить или заменить. Но начинать не оттуда.

Когда Netdata поймала то, что стало бы инцидентом

Три конкретные истории. Ни одна не показалась бы на «healthcheck сервиса доступен» — к моменту, когда тот переключится в красное, клиенты уже пишут.

Случай 1

Тихий swap-storm

Симптомы. Бэкенд API утром начал отдавать случайные 500-е. Latency-дашборд показывал повышенный p95 без явной причины. CPU — «нормально». Первый инстинкт команды — «перезапустить и посмотреть».

Что показала Netdata. На графике mem.swapio последние 36 часов тихо рос swap-out. Свободная память — около нуля. Ядро thrash’ило — CPU был «нормально», потому что просто ждал диск, а не делал ничего полезного.

Решение. Предыдущий конфиг-rollout увеличил pool size в 5 раз, headroom’а под него на сервере уже не было, и любая мелкая аллокация утекала в swap. Откатили конфиг. Добавили алерт на system.ram available_percent < 15 и второй на mem.swapio out > 1MB/s в течение 5 минут. Теперь такая memory creep будит нас за сутки до того, как пользователи заметят.

Случай 2

Утечка памяти, которая копилась неделю

Симптомы. Python-воркер дрейфовал с ~400 МБ до ~3.5 ГБ за шесть дней. Без падений — на сервере было место, — но каждый деплой с рестартом ресетил утечку и маскировал её от любого мониторинга, который смотрит только на текущее значение RAM.

Что показала Netdata. График apps.mem для этого процесса — красивая линейная рампа. Рестарты на нём — чёткие падения, шесть штук за неделю. Как только паттерн стал виден, причина (кэш без eviction policy) — 30 минут с tracemalloc.

Решение. Ограничили кэш, добавили алерт на apps.mem, если воркер превысит 1 ГБ, повторили охоту на утечки с алертом как safety net. Без истории по памяти на процесс, переживающей рестарты, утечка крутилась бы до тех пор, пока OOM killer не сделал бы её всеобщей.

Случай 3

Шумный сосед на общем диске

Симптомы. Postgres на VPS начал тормозить в произвольные моменты. EXPLAIN — нормально. Коннекшены — нормально. CPU — нормально.

Что показала Netdata. disk.iops и disk.await скакали вместе, при этом наш собственный disk.io в МБ/с был скромным — то есть это не мы делаем эти IOPS. Хост был shared, и сосед стал шумным.

Решение. Переехали с Postgres на хост с выделенным NVMe. Добавили алерт disk.await > 50ms в течение 5 минут, чтобы в следующий раз, когда сосед проснётся, мы знали об этом за минуты, а не за часы клиентских жалоб.

Быстрый старт: от нуля до полезных графиков за 10 минут

Если вы прямо сейчас пробуете на одном сервере, вот мой путь.

1. Установить агент. Официальный kickstart-скрипт сам определит дистрибутив, проверит подписи и пропишет systemd.

bash
# установка одной строкой (Linux)
wget -O /tmp/netdata-kickstart.sh https://get.netdata.cloud/kickstart.sh
sh /tmp/netdata-kickstart.sh --stable-channel --disable-telemetry

2. Закрыть дашборд. Дефолтный порт 19999 ни в коем случае не должен смотреть в интернет. Биндим на localhost и заходим через SSH-туннель.

/etc/netdata/netdata.conf
[web]
    bind to = 127.0.0.1

Дальше с ноутбука:

bash
ssh -L 19999:localhost:19999 user@your-host
# открыть http://localhost:19999 в браузере

3. Тюнинг алертов, которые важны. Дефолты разумные, но шумные. Те, что я всегда правлю в первый день:

  • system.ram — процент свободной памяти.
  • mem.swapio — постоянный swap-out.
  • disk.space — и rate заполнения, и абсолютные %.
  • disk.await — задержки на чтение/запись.
  • Postgres / MySQL / Redis connection saturation, если что-то из этого есть.

Файлы лежат в /etc/netdata/health.d/. Перезагрузка — netdatacli reload-health, без рестарта.

4. Подключить нотификации. Правим /etc/netdata/health_alarm_notify.conf и выбираем канал. Telegram самый лёгкий: bot token + chat ID, и всё. Slack работает похоже — webhook URL.

Pro tip. Выключайте десятки графиков, которые вам не нужны. Netdata с радостью нарисует температуру каждого NVMe-сенсора — смотреть на это всё необязательно. Глушите агрессивно — дашборд, на котором ничего лишнего, заслуживает больше доверия.

Масштаб: parent–child для парка серверов

На одном хосте Netdata-агент и собирает, и хранит метрики. Когда у тебя больше горсти нод, не хочется логиниться на каждую, чтобы посмотреть графики, и хочется хранить дольше, чем влезает на одну ноду.

Модель parent–child решает обе проблемы:

  • Children запускают облегчённого агента, который собирает метрики и стримит их на parent.
  • Parents принимают потоки от множества children и хранят их централизованно столько, сколько нужно.

Топология, которая хорошо заходит для маленького парка: app/web/db ноды как children, один parent на отдельной VM с щедрым SSD. Алерты крутятся на parent, children только собирают.

                  ┌──────────────────────┐
                  │   parent-monitor     │
                  │   30d retention      │
                  │   alerts → telegram  │
                  └──────────▲───────────┘
                             │ stream
        ┌────────────────────┼────────────────────┐
        │                    │                    │
   ┌────┴────┐          ┌────┴────┐          ┌────┴────┐
   │ web-01  │          │ db-01   │   …      │ bg-01   │
   │  child  │          │  child  │          │  child  │
   └─────────┘          └─────────┘          └─────────┘
            children: только сбор · 1ч локального кэша

Настройки, которые трогаю:

  • /etc/netdata/stream.conf на каждом child: API key + URL parent’а.
  • Тот же файл на parent’е: список разрешённых children с тем же API key.
  • Секция [db] в netdata.conf на parent’е: подкручиваю multi-tier retention — несколько недель в высоком разрешении, несколько месяцев в downsampled tier’ах.
  • Все алерты — на parent, чтобы тюнить в одном месте.

Когда parent–child не нужен: одна нода или маленький кластер, где встроенного дашборда на каждом агенте хватает. Цена не запредельная, но и не нулевая, и parent — это ещё одна штука, за которой надо следить.

Практические best practices

Что я вынес из эксплуатации этого в небольшом масштабе:

  • Тюньте под сигнал, а не покрытие. Дефолтная Netdata показывает много. Глушите графики, в которые не смотрите. Будет больше доверия к дашборду, и вы быстрее заметите аномалию.
  • Ежедневный взгляд, недельный обзор. Каждый день: открыть parent, прошерстить RAM/swap/disk-await/error-rate на топ-хостах. Раз в неделю: пройтись по истории алертов и поправить пороги для всего, что бузило, но не должно было.
  • Покажите не-инженерам человеческий вид. Полный дашборд страшный. Кастомная страница «API latency, error rate, queue depth» гораздо полезнее продакту, чем стена терминологии ядра.

Анти-паттерны, которые кусают сильнее всего:

  • Открыть порт 19999 наружу. Не надо.
  • Оставить все дефолтные алерты в Slack, пока не замьютите канал.
  • Реагировать на каждый жёлтый. Жёлтый существует, чтобы на него посмотрели, не чтобы по нему будили.
  • Забыть, что parent теперь — single point of failure для видимости. Бэкапьте его конфиг; рассмотрите второй parent, если uptime самого мониторинга — требование.

Где Netdata вписывается в observability

Netdata — это слой метрик и реалтайм-алертов. Это не система логов, и это не tracing. Модель, которую я использую:

  • Netdata — метрики хоста и сервисов, реалтайм, алерты.
  • Логи — в централизованном хранилище (Loki, ELK или managed solution) для разборов постфактум.
  • Tracing — только когда есть многосервисный граф запросов, который этого требует. Для маленького парка достаточно структурированных логов плюс Netdata.

Маршрутизация алертов — скучная намеренно: Netdata → Telegram мне, Slack команде. Не оверинженирьте alert pipeline до того, как поняли, какие алерты реально важны.

Заключение

Три года эксплуатации Netdata на проде превратили примерно столько же инцидентов в minor merge requests вместо реальных простоев. Цена — одна команда установки, конфиг с bind to 127.0.0.1, час на тюнинг алертов и дисциплина глушить графики, в которые не смотришь.

Если у вас Linux в проде и нет мониторинга, которому вы доверяете, — поставьте Netdata сегодня на один сервер. Биндитесь на localhost, заходите через туннель, посмотрите графики десять минут. Найдёте как минимум одну вещь, о которой не знали.