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=ingest | HTTP-приём: эндпоинты Sentry envelope и OTLP-метрики, батчинг событий/спанов/метрик/профилей, вычисление оповещений по принятым данным |
--mode=web | SSR-веб-интерфейс (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 Vitals | 90 дней |
| Спаны трейсов | 30 дней |
| Метрики (OTLP) | 30 дней |
| Профили | 7 дней (самые тяжёлые по объёму) |
Каждое значение настраивается переменной окружения (GOTCHA_RETENTION_DAYS,
GOTCHA_SPAN_RETENTION_DAYS и т. д.) и применяется на следующем старте как TTL
на таблицах ClickHouse. Подробности — Конфигурация.
Что даёт архитектура для приватности
Так как всё self-hosted, событийные данные — часто самые чувствительные логи в системе — не покидают вашу инфраструктуру. Плюс несколько защит встроены на уровне архитектуры:
- SSRF-защита исходящих запросов (аптайм-проверки, webhook-алерты) — по умолчанию они не могут обращаться к приватным/loopback-адресам, чтобы один пользователь не превратил проверку в сканер вашей внутренней сети.
- Контроль текста ошибок во внешних каналах — можно отправлять в Telegram/webhook только обезличенную ссылку, без тела ошибки (в нём могут быть персональные данные).
- Подпись сессионных cookie отдельным секретом; на не-localhost адресе
приложение отказывается стартовать в режимах
web/allбез своего ключа.
Коротко
Gotcha намеренно устроена «скучно»: один бинарник, две базы, один флаг для раскладки по процессам. Это компромисс в пользу простоты эксплуатации self-hosted-инстанса. Как поднять — Установка; все переменные — Конфигурация; как подключить приложение — SDK и интеграции.