Хабр, привет!

Это история о том, как желание просто проверить, жив ли мой блог, привело к трём дням танцев с бубном вокруг SSL-сертификата, а затем — к созданию собственного сервиса мониторинга, который теперь используют сотни разработчиков. Расскажу, почему существующие решения перестали устраивать, как мы реализовали поддержку UDP и ICMP в облаке и почему мониторинг должен быть «скучным».

Предыстория: как я стал сисадмином мониторинга

Год назад у меня была простая задача: настроить уведомления о падении личного блога и API пары пет-проектов. Думал, уложусь в 15 минут.

Спойлер: не уложился.

Я решил попробовать self-hosted решение — Uptime Kuma. Отличный опенсорс-проект, ничего не скажешь. Но:

  1. Нужен был сервер (или хотя бы VPS).

  2. Настройка Docker + обратный прокси + Let's Encrypt для статус-страницы заняла вечер.

  3. Через месяц пришло обновление, которое сломало совместимость с моей версией Node.js.

Я понял, что трачу больше времени на поддержку инструмента для наблюдения, чем на код, который этот инструмент должен защищать.

Боль существующих решений (субъективно, но честно)

Я прошерстил всё, что есть на рынке, и выделил ключевые проблемы.

1. UptimeRobot

Плюсы: Бесплатный порог входа, простой.
Минусы: Алерты приходят с задержкой 5-10 минут. Для продакшна это критично. За 5 минут пользователи успевают уйти к конкурентам, а поисковые боты - задетектить падение. Плюс - только HTTP и TCP. Ни UDP, ни ICMP.

2. Pingdom

Плюсы: Надёжный, много фич.
Минусы: Цена. $20/мес за мониторинг небольшого проекта - жирновато. Кредитка для триала - отдельный раздражитель.

3. Self-hosted (Uptime Kuma, Prometheus + Alertmanager)

Плюсы: Полный контроль, гибкость.
Минусы: Требует инфраструктуры и времени на поддержку. Обновления, безопасность, бэкапы - всё ложится на вас. Если у вас нет выделенного DevOps-инженера, это оверхед.

4. Better Stack

Плюсы: Красивый интерфейс, хорошие интеграции.
Минусы: Ценовая политика. UDP-мониторинг и многие другие «нишевые» фичи - только в дорогих тарифах.

5. Отдельная боль - UDP и ICMP

Большинство SaaS-мониторов вообще не умеют работать с UDP. А если умеют - это enterprise-функция за долларов в месяц.

Зачем вообще нужен UDP-мониторинг?

  • Игровые сервера (Minecraft, CS:GO, Rust) - работают поверх UDP.

  • DNS-серверы - без UDP они не живут.

  • Собственные приложения на UDP (например, syslog-коллекторы, трекеры).

  • Просто проверить, отвечает ли хост на ICMP-запросы (ping), чтобы понять, жив ли сервер, даже если веб-сервер упал.

Как мы строили PingZen

Я решил, что хочу инструмент, который:

  • не требует моей инфраструктуры;

  • поддерживает HTTP, TCP, UDP и ICMP «из коробки»;

  • доставляет алерты быстро (без искусственных задержек);

  • и при этом остаётся бесплатным для небольших проектов.

Так родился PingZen.

Архитектура (кратко)

В отличие от многих корпоративных решений, мы не стали с самого начала строить распределённую сеть проверок по всему миру. Вместо этого сделали упор на надёжность и простоту: все проверки выполняются с одного сервера в Yandex Cloud (регион «Москва»). Этого оказалось достаточно для быстрой и точной диагностики для нашей аудитории, а риск ложных срабатываний мы свели к минимуму за счёт умной логики повторов.

Как работает UDP-мониторинг

  1. Пользователь указывает хост и порт (например, mc.example.com:25565 для Minecraft).

  2. Наш checker формирует UDP-пакет (для Minecraft — handshake-пакет, для DNS — запрос типа A).

  3. Если в течение таймаута приходит ответ — сервис жив. Если нет — фиксируем неудачу.

Важно:  UDP не гарантирует доставку, поэтому мы не полагаемся на одиночную потерю пакета. Перед тем как объявить сервис упавшим, checker выполняет несколько последовательных попыток с одной ноды (current_failure_streak). Например, при настройке confirmation_threshold = 3 монитор перейдёт в статус DOWN только после трёх неудачных проверок подряд.

ICMP-мониторинг

Реализован максимально просто и надежно — через вызов стандартной утилиты ping (asyncio.create_subprocess_exec). Никаких сырых сокетов и прав CAP_NET_RAW, которые усложняют жизнь в контейнерах. Это решение отлично работает и не требует особых привилегий.

HTTP(S) и TCP

Всё стандартно: проверка кодов ответа, таймаутов, валидация тела ответа (например, поиск подстроки в JSON). Для HTTPS проверяем валидность сертификата.

Стек (честно о том, что работает)

Когда я начинал писать PingZen, у меня не было цели строить распределенный кластер на Kubernetes с микросервисами на разных языках. Цель была — сделать надежный и полезный инструмент, используя проверенные и понятные технологии. Поэтому стек получился прагматичным и мощным.

  • Бэкенд: Единое приложение на Python 3.13 + FastAPI. Никакой микросервисной распределенщины там, где она не нужна. FastAPI дает асинхронность «из коробки» и невероятную скорость разработки. Весь код мониторинга, API и бизнес-логики — в одном месте.

  • База данных: Основное хранилище — PostgreSQL 17. Для метрик и временных рядов мы не стали усложнять и использовать TimescaleDB (хотя это отличное решение), а выбрали специализированный инструмент — VictoriaMetrics. Он легкий, быстрый и отлично интегрируется с нашей архитектурой.

  • Брокер сообщений и очереди: Вместо RabbitMQ мы используем встроенные возможности Redis с кастомными Lua-скриптами для реализации надежной очереди проверок CheckQueue. Это позволило держать стек минимальным, но при этом получить всю необходимую функциональность.

  • Инфраструктура: Никакого Kubernetes на старте. Весь сервис работает на одном VPS в Yandex Cloud под управлением Docker Compose. Это радикально упрощает деплой и поддержку, а ресурсов одного сервера с лихвой хватает на текущую нагрузку (около 200 мониторов). Единый регион проверок — DEFAULT_REGION = "Moscow, RU", что обеспечивает предсказуемость и низкую задержку для нашей аудитории.

Особенности реализации, которые действительно важны

  • Механизм подтверждения сбоев (Confirmation Count): В статье я писал про проверки с разных нод. Но на самом деле механизм даже интереснее. В PingZen реализован счетчик current_failure_streak. Он работает в рамках одной ноды, но последовательно. Например, если вы установили порог подтверждения сбоя в 3, монитор не объявит сервис упавшим после первого таймаута. Он сделает еще две проверки подряд, и только если все они неудачны - зафиксирует проблему. Это надежно отсеивает случайные потери пакетов, не требуя распределенной инфраструктуры.

  • Как мы реально проверяем ICMP и UDP: Мы не лезем в сырые сокеты с CAP_NET_RAW, так как это усложняет контейнеризацию. Вместо этого мы используем стандартный и надежный способ: asyncio.create_subprocess_exec("ping", ...) для ICMP. Для UDP - асинхронная отправка и прием пакетов через asyncio с контролем таймаутов. Это работает стабильно и код легко поддерживать. А для "специфичных" протоколов, вроде Minecraft handshake, мы написали отдельные модули, которые формируют правильные пакеты поверх обычного UDP. И да, они работают! (Проверить работу UDP-монитора для своего Minecraft-сервера можно здесь).

  • Скорость алертов: Мы не гонимся за мифической "мгновенностью", потому что это часто приводит к ложным срабатываниям. Задержка алерта предсказуема и зависит напрямую от заданного вами интервала проверки. Если проверка идет раз в минуту, алерт придет максимум через 60 секунд после сбоя. Для 99% задач этого достаточно. Мы выбрали надежность и честность вместо пустых обещаний.

  • Статус-страницы: В текущей версии статус-страницы генерируются динамически FastAPI-эндпоинтами и рендерятся на клиенте. Это дает нам гибкость в кастомизации и не требует сложной системы сборки статики. В будущем, возможно, добавим опцию статической генерации, но и текущее решение отлично работает.

Технические детали для интересующихся

Как мы боремся с false positives

У нас есть настройка Confirmation Count - сколько последовательных неудачных проверок с разных нод нужно, чтобы считать сервис упавшим. По умолчанию - 2. Это позволяет отсекать случайные сетевые глюки.

Мониторинг UDP на практике

Чтобы проверить Minecraft-сервер, мы отправляем пакет 0xFE (server list ping) и ждём ответа с описанием сервера. Для DNS - отправляем запрос типа A на google.com и ждём ответ с кодом NOERROR.

JSON-валидация для API

Можно указать JSONPath (например, $.status) и ожидаемое значение (ok). Если ответ не соответствует - монитор падает.

Что дальше

Сейчас PingZen мониторит больше 500 проектов - от портфолио до продакшн-бэкендов. Мы активно собираем фидбек и планируем:

  • добавить проверки по GraphQL;

  • сделать более глубокую интеграцию с PagerDuty и Opsgenie;

  • реализовать «умные» эскалации (если через 5 минут не ответил в Telegram — дублируем в SMS).

Но главное - мы хотим, чтобы сервис оставался простым и полезным.

Сам по себе pingzen.dev бесплатный на данный момент и еще долго будет. Он все еще на стадии разработки. Ноо, уже сейчас можете создать неограниченное количество мониторов и использовать весь функционал. Основа в рабочем состоянии.

Так что, если заинтересованы - это отличная возможность попробовать что-то новое и упростить себе жизнь.

Мне очень интересна обратная связь.

  • Что используете для мониторинга сейчас?

  • Какие фичи вам реально нужны?

Возможно есть что-то еще ,что я могу сделать чтобы наша жизнь стала чуточку проще :-)

Я отвечу на все вопросы. Спасибо, что дочитали! 🍻