Observability в одном Go-бинарнике: как устроена Gotcha

Gotcha — это один Go-бинарник поверх двух хранилищ: PostgreSQL и ClickHouse. Ни брокера сообщений (Kafka), ни кэша (Redis) в схеме нет. Тот же бинарник флагом --mode превращается в приёмник данных, веб-интерфейс, раннер аптайма или выносную пробу — либо запускает всё это в одном процессе (--mode=all). Ниже — из чего это собрано и почему так.

Из чего состоит Gotcha

Вся система — три контейнера в штатном docker-compose.yml: приложение gotcha, postgres и clickhouse. Два хранилища делят ответственность по природе данных:

ХранилищеЧто держит
PostgreSQLРеляционное состояние: организации, проекты, пользователи, правила оповещений, инциденты
ClickHouseВысокочастотные данные: события (ошибки), спаны трейсов, метрики, профили, результаты аптайм-проверок

Такое разделение естественно: метаданные — это транзакционная реляционка (Postgres), а поток телеметрии — колоночная аналитика с большими объёмами записи и TTL (ClickHouse).

Почему без Kafka и Redis?

Приём данных (--mode=ingest) сам батчит события, спаны, метрики и профили и пишет их в ClickHouse, который рассчитан на высокую пропускную способность вставки. Для self-hosted-наблюдаемости этого достаточно — отдельный брокер между приёмом и хранилищем не нужен. Состояние сессий и вычисления оповещений живут в PostgreSQL и в самом процессе, поэтому и внешний кэш не требуется. Практический итог: меньше движущихся частей, меньше памяти и проще эксплуатация, чем у стеков с Kafka + Redis + несколькими сервисами.

Что делает флаг –mode?

Один и тот же бинарник gotcha принимает флаг --mode, который включает часть функций. Это позволяет и запустить всё в одном процессе, и разнести нагрузку по отдельным процессам при росте.

РежимЧто делает
--mode=ingestHTTP-приём: эндпоинты Sentry envelope и OTLP-метрики, батчинг событий/спанов/метрик/профилей, вычисление оповещений по принятым данным
--mode=webSSR-веб-интерфейс (templ + htmx): аутентификация, администрирование организаций/проектов, дашборды, публичные статус-страницы
--mode=uptimeРаннер аптайм-проверок, watchdog инцидентов, вычислители регрессий производительности и порогов по метрикам
--mode=probeВыносная аптайм-проба: общается только с центральным инстансом по HTTP, без прямого доступа к базам
--mode=allВсё перечисленное в одном процессе — режим по умолчанию для небольшой self-hosted-установки

Как это масштабируется

Пока нагрузка небольшая — --mode=all держит всё в одном процессе. Когда приём начинает конкурировать с веб-интерфейсом за ресурсы, те же функции разносятся по отдельным процессам: несколько ingest-инстансов за балансиром, отдельный web, отдельный uptime. А --mode=probe разворачивается в другом регионе или дата-центре и проверяет доступность ваших сервисов «снаружи» — проба не открывает ни PostgreSQL, ни ClickHouse, только ходит к центральному инстансу по HTTP. То есть масштабирование — это не смена архитектуры, а запуск того же бинарника с другим --mode.

Как хранятся данные и retention

ClickHouse хранит каждый тип телеметрии заданное число дней, после чего старые записи удаляются по TTL. Дефолты подобраны по «весу» данных:

Тип данныхRetention по умолчанию
События, транзакции, Web Vitals90 дней
Спаны трейсов30 дней
Метрики (OTLP)30 дней
Профили7 дней (самые тяжёлые по объёму)

Каждое значение настраивается переменной окружения (GOTCHA_RETENTION_DAYS, GOTCHA_SPAN_RETENTION_DAYS и т. д.) и применяется на следующем старте как TTL на таблицах ClickHouse. Подробности — Конфигурация.

Что даёт архитектура для приватности

Так как всё self-hosted, событийные данные — часто самые чувствительные логи в системе — не покидают вашу инфраструктуру. Плюс несколько защит встроены на уровне архитектуры:

Коротко

Gotcha намеренно устроена «скучно»: один бинарник, две базы, один флаг для раскладки по процессам. Это компромисс в пользу простоты эксплуатации self-hosted-инстанса. Как поднять — Установка; все переменные — Конфигурация; как подключить приложение — SDK и интеграции.

Исходный код открыт (Apache-2.0): GitHub · GitFlic.