Мониторинг и метрики
Что смотреть ежедневно, какие показатели важны и как подключить внешний мониторинг.
Наблюдать за системой можно с трёх сторон: админка (быстрый ежедневный обход), JSON API (для внешней системы мониторинга) и метрики ноды в формате Prometheus (для сбора временных рядов и оповещений).
Метрики в формате Prometheus отдаёт стриминговая нода — эндпоинт /metrics на её
HTTP-порту. Контрол-плейн (Plane) такого эндпоинта не имеет: его показатели доступны
только через авторизованный JSON API и админку. Не ищите /metrics на Plane — его там нет.
Ежедневный обход#
Пять проверок, занимают пару минут. В админке всё это — раздел Мониторинг и раздел Ноды.
| Что проверить | Где смотреть | Норма |
|---|---|---|
| Доступность нод | Мониторинг → Состояние | Все ноды доступны, «Требуют внимания» — ноль |
| Камеры в эфире | Мониторинг → Состояние | Число совпадает с числом включённых камер |
| Лицензии | Ноды → карточка → Лицензия | Нет нод без лицензии и в состоянии grace |
| Заполнение дисков | Ноды → карточка → Хранилища | Заполнение стабильно у порога вытеснения, растёт не скачками |
| Ошибки в журналах | Мониторинг → Логи Plane, Ноды → карточка → Логи | Нет повторяющихся ошибок |
То же самое одной командой, если удобнее в терминале:
BASE=https://cctv.example.com TOKEN=$(curl -sS -X POST "$BASE/api/v1/auth/login" -H 'Content-Type: application/json' \ -d '{"login":"admin","password":"ВАШ-ПАРОЛЬ"}' \ | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])') curl -sS "$BASE/api/v1/monitor/fleet/summary" -H "Authorization: Bearer $TOKEN" \ | python3 -m json.tool
{ "seq": 1841, "sampled_at": "2026-08-18T09:14:22Z", "nodes_total": 3, "nodes_reachable": 3, "stream_samples_stale": 0, "streams_total": 412, "streams_live": 410, "streams_degraded": 2, "streams_failing": 0, "cameras_total": 206, "cameras_live": 205, "cameras_unavailable": 1, "nodes_unlicensed": 0, "nodes_grace": 0 }
Это самая полезная одиночная проверка: одним запросом видно и доступность нод, и состояние камер, и лицензии.
Показатели ноды в админке#
Ноды → нода → Обзор показывает срез телеметрии. Значения означают следующее.
| Показатель | Что это | На что смотреть |
|---|---|---|
| CPU процесса | Сколько ядер занимает сам сервис ноды | Сравнивайте с числом рабочих ядер: 8 из 16 — половина запаса израсходована |
| CPU хоста | Загрузка всего сервера, включая посторонние процессы | Если хоста загружено много, а процесса — мало, конкурент за ресурсы вне системы |
| RSS процесса | Занятая процессом оперативная память | Должна выходить на плато и держаться; постоянный рост — повод завести обращение |
| Память хоста | Свободная память сервера | Меньше 10 % свободной — риск вытеснения в своп и рывков видео |
| Ядра CPU (тепловая карта) | Загрузка каждого рабочего ядра | Перекос (одно ядро горячее, остальные простаивают) — почти всегда ошибка в параметре cores |
| Открытые FD | Файловые дескрипторы процесса | Растут с числом камер и зрителей; резкий рост без роста нагрузки — утечка соединений |
| Ошибки UDP, потери ядра и очереди | Потери на приёме UDP | Любой устойчивый рост означает потерю кадров — см. Производительность |
| RX в очереди | Данные, не забранные из сокета | Устойчиво ненулевое значение = нода не успевает разбирать входящий поток |
Если тепловая карта показывает, что работает только первое ядро, у ноды выставлено
cores 1 или другое малое значение. cores 0 означает «использовать все производительные
ядра» — это правильное значение по умолчанию. Меняется в админке: Ноды → нода → Сеть и TLS
→ Рабочие ядра (применяется при следующем перезапуске ноды).
Вкладка Сессии показывает текущих зрителей этой ноды: протокол, клиент, исходящий трафик, потери, джиттер и отставание. Устойчивые потери у одного клиента — проблема его канала; потери сразу у всех — проблема ноды или сети до неё.
Подключение внешней системы мониторинга#
Что опрашивать у Plane#
Все эндпоинты, кроме /health, требуют токена суперадминистратора.
| Эндпоинт | Период опроса | Что даёт |
|---|---|---|
GET /health |
15–30 с | Живость Plane и доступность базы. Без авторизации — идеально для проверки доступности |
GET /api/v1/monitor/fleet/summary |
30–60 с | Сводка по флоту: ноды, камеры, потоки, лицензии |
GET /api/v1/monitor/plane |
1–5 мин | История ресурсов Plane: 900 точек с шагом 2 с (последние 30 минут) |
GET /api/v1/nodes |
60 с | Список нод: state, version, last_seen_at |
GET /api/v1/sessions |
по необходимости | Кто и что смотрит прямо сейчас |
# живость — самая простая проверка, годится для любого монитора доступности curl -sS -o /dev/null -w '%{http_code}\n' "$BASE/health" # 200 — сервис жив и база доступна; 503 — база недоступна # ресурсы Plane: последняя точка истории curl -sS "$BASE/api/v1/monitor/plane" -H "Authorization: Bearer $TOKEN" \ | python3 -c 'import sys,json;s=json.load(sys.stdin)["samples"][-1];print(s["proc_cpu_cores"], s["rss_mb"], s["open_fds"], s["db_pool_in_use"], "/", s["db_pool_max"])' # 0.04 118 96 2 / 16
Поле proc_cpu_cores — это доля ядер, посчитанная по приросту процессорного времени, а не
мгновенный снимок загрузки. Его можно использовать напрямую, без усреднения.
Сессионный токен по умолчанию действителен 1 час (session_ttl_secs в plane.toml). Скрипт
мониторинга должен получать токен заново, а не хранить его вечно: иначе через час опрос начнёт
получать 401. Проверку доступности стройте на /health — она вообще не требует токена.
Для живых панелей вместо периодического опроса есть потоки событий (SSE):
GET /api/v1/monitor/fleet/summary/stream, GET /api/v1/monitor/nodes,
GET /api/v1/monitor/plane/stream. Полное описание всех полей и кодов ответа —
Мониторинг и служебное.
Метрики ноды в формате Prometheus#
Каждая нода отдаёт метрики на своём HTTP-порту:
curl -sS http://node.example.com:8090/metrics | head -20
| Метрика | Тип | Смысл |
|---|---|---|
hastreamer_process_cpu_cores |
gauge | Загрузка процесса в ядрах |
hastreamer_worker_cores |
gauge | Сколько рабочих ядер настроено |
hastreamer_process_rss_bytes |
gauge | Занятая память процесса |
hastreamer_host_cpu_busy_ratio |
gauge | Загрузка хоста, доля от 0 до 1 |
hastreamer_host_cpus |
gauge | Логических ядер на хосте |
hastreamer_mem_total_bytes, hastreamer_mem_available_bytes |
gauge | Память хоста: всего и доступно |
hastreamer_open_fds |
gauge | Открытых файловых дескрипторов |
hastreamer_uptime_seconds |
gauge | Время работы процесса |
hastreamer_streams |
gauge | Потоков на ноде |
hastreamer_sessions |
gauge | Активных сессий раздачи |
hastreamer_stream_no_data_seconds{stream="…"} |
gauge | Секунд без данных от источника, по каждому потоку |
hastreamer_stream_ingest_latency_ms{stream="…"} |
gauge | Задержка приёма, по каждому потоку |
hastreamer_udp_ingest_kernel_drops_total |
counter | Датаграммы, потерянные в буфере ядра |
hastreamer_udp_ingest_queue_dropped_total |
counter | Датаграммы, потерянные в очереди приложения |
hastreamer_udp_ingest_recv_errors_total |
counter | Ошибки приёма UDP |
hastreamer_streams_omitted |
gauge | Потоки, для которых серии не выгружены (ограничение — 500 потоков) |
Значения hastreamer_udp_ingest_* меняются только при работе с камерами по RTSP/UDP; при
транспорте TCP (значение по умолчанию) они остаются нулевыми.
/metrics доступен без авторизацииТак принято для систем сбора метрик, но это значит, что состав потоков и загрузка ноды видны
любому, кто может открыть её HTTP-порт. Если нода доступна из интернета — ограничьте доступ
к /metrics межсетевым экраном:
# разрешить сбор метрик только с адреса системы мониторинга sudo ufw allow from <IP-системы-мониторинга> to any port 8090 proto tcp comment 'metrics scrape'
Проще всего — держать порт ноды доступным только из сети мониторинга, а видео раздавать через отдельный HTTPS-порт.
На что настраивать оповещения#
| Условие | Почему важно |
|---|---|
GET /health не отвечает или отдаёт 503 |
Plane или база недоступны |
nodes_reachable меньше nodes_total |
Нода выпала из флота |
nodes_unlicensed или nodes_grace больше нуля |
Скоро остановится видео на этой ноде |
cameras_unavailable растёт |
Камеры теряются: сеть, питание, учётные данные |
hastreamer_stream_no_data_seconds больше 60 |
Поток жив в конфигурации, но данные не идут |
Рост hastreamer_udp_ingest_*_total |
Потери на приёме — теряются кадры |
hastreamer_process_rss_bytes подходит к пределу памяти юнита |
Процесс упрётся в ограничение cgroup |
hastreamer_streams резко уменьшилось |
Часть камер отвалилась или сработал лимит лицензии |
Журналы#
# Plane sudo journalctl -u hastreamer-cctv-plane -n 100 --no-pager sudo journalctl -u hastreamer-cctv-plane -p err --since '24 hours ago' --no-pager # нода sudo journalctl -u hastreamer-cctv-node -n 100 --no-pager sudo journalctl -u hastreamer-cctv-node -f
Те же записи доступны без доступа к серверу: Мониторинг → Логи Plane и Ноды → нода → Логи. В админке журнал хранится в кольцевом буфере ограниченного размера — для долгого хранения настраивайте выгрузку journald своими средствами.
Кнопки уровней в админке фильтруют уже сохранённые записи. Чтобы получить более подробные
записи, нужно поднять уровень логирования сервиса (log_level в
plane.toml или node.conf). У ноды
log_level применяется без перезапуска.
Что смотреть, когда «стало хуже»#
| Наблюдение | Первый шаг |
|---|---|
| Видео тормозит у всех зрителей одной ноды | CPU процесса и потери очереди на этой ноде — Производительность |
| Видео тормозит у одного зрителя | Вкладка «Сессии»: потери и джиттер именно его сессии — проблема его канала |
| Камера то появляется, то пропадает | Журнал ноды по этой камере; связность: nc -vz <адрес-камеры> 554 |
| Админка отвечает медленно | GET /api/v1/monitor/plane: db_pool_in_use близок к db_pool_max — расширьте пул |
| Архив внезапно стал короче | Диск заполнился и включилось вытеснение — Хранилища DVR |
Подробный разбор по симптомам — Диагностика неисправностей.