Прямой ответ
Коллектор телеметрии — единая точка приёма/обработки/экспорта сигналов (метрики+логи+трейсы идут через один конвейер, а не тремя самописными путями в три бэкенда — три столпа — «приложение шлёт в OTel, дальше — проблема пайплайна» — развязка кода и инфраструктуры — 12-factor-конфигурация); OTel Collector (вендор-нейтральный стандарт — компоненты: receivers (otlp — главный; prometheus — скрейпы существующих /metrics (метрики-практика); filelog — хвосты лог-файлов; journald/kafka/hostmetrics — «всё в один вход»), processors (batch — обязательный (батчинг перед экспортом — эффективность сети/бэкенда), memory_limiter — защита самого коллектора от OOM (graceful-культура), attributes/resource — нормализация меток (service.name/env/version — структура-меток — «у половины сервисов service=app» — процессор чинит centrally), filter — дроп шума, tail_sampling — умная выборка трейсов — см. ниже), exporters (prometheusremotewrite, loki, otlp/tempo — бэкенды — Alloy/Loki/TUI-стек); конфигурация — YAML-пайплайны (pipelines: traces: [receivers] → [processors] → [exporters] — отдельные пайплайны на сигнал — читаемо и отлаживаемо); Grafana Alloy — дистрибутив коллектора от Grafana (тот же OTel-движок + синтаксис River (компоненты-блоки с ссылками — не YAML, а граф — «prometheus.scrape → otelcol.processor.batch → loki.write» — компоненты связываются явно) + встроенные интеграции (scrape-конфиги/journald/eBPF-профили (Pyroscope-связка) — Grafana-стек-удобство); выбор: Grafana-стек (Loki/Tempo/Mimir/Pyroscope) — Alloy (интеграции из коробки — один агент на ноду — метрики+логи+трейсы+профили — DaemonSet — k8s-контекст); мульти-вендор/свой стек — голый OTel Collector (нейтральность — экспорт куда угодно — выбор-контекст); оба — одна экосистема компонентов (OTel-совместимость — миграция Alloy↔Collector — конфиги конвертируемы частично — «выбрали и заперлись» — нет); tail sampling (главная прод-фича для трейсов): решение «оставить ли трейс» по полному трейсу (не по голове — probabilistic head-sampling режет до попадания — «ошибочный трейс срезался» — боль); tail-политики: ошибки — 100%, латентность > p99 — 100%, остальное — 5–10% (процентилям — «все ошибки и все медленные + выборка нормы» — 20% стоимости хранения, 100% полезного — Tempo-контекст — память на окно трейса — ёмкость); деплой-топологии: агент (DaemonSet/sidecar — приём локально, лёгкая обработка, отправка дальше — «сеть до бэкенда рвётся — буфер на месте») + гейтвей (центральный кластер коллекторов — тяжёлые процессоры (tail_sampling требует видеть все спаны трейса — только гейтвей), экспорт в бэкенды — два слоя — стандарт прод-архитектуры; отказоустойчивость: коллектор — stateful по буферам (очереди-контекст — persistent queue на диск — бэкенд лёг — телеметрия не потеряна (минуты-часы буфера — retry-механика экспортёра).
Практика: пайплайны, процессоры, миграция
Конфиг-каркас (Collector YAML): receivers — otlp (grpc 4317/http 4318 — SDK-подключение), prometheus (скрейп легаси-/инфра-таргетов), filelog (логи контейнеров — Loki-альтернатива — прометейл-замена); processors — memory_limiter (80% RAM — защита — память-дисциплина), batch (200ms/8192 — дефолты хороши), resource-нормализация (service.name из env/меток пода — конфигурация), transform (OTTL — «переименовать атрибут/извлечь поле» — лёгкая обработка без кода — обработка-контекст); exporters — по бэкендам + sending_queue (persistent-очередь — надёжность); миграция существующего стека (постепенная, не «одним днём»): (1) коллектор параллельно (приложения продолжают слать в старое — коллектор скрейпит/принимает копию — двойное писание — сравнение полноты — данные-сверка); (2) перевод сервисов на OTLP (SDK — endpoint — коллектор — по сервису за PR — техдолг-волны); (3) отключение старых путей (promtail/fluentd-агенты снимаются — «три агента на ноду» → один — ёмкость-экономия — CPU/RAM нод — измеримо — метрики); (4) мониторинг самого коллектора (internal-метрики — очередь/дропы/экспорт-ошибки — алерты — «коллектор дропает» — видно — health-эндпоинт (healthcheck).
Практический сценарий: три агента и ручная корреляция → один пайплайн
Контекст: 25 сервисов, телеметрия-зоопарк: метрики — Prometheus-скрейп напрямую, логи — promtail→Loki, трейсы — Jaeger-агент→Tempo (три агента на ноду, три конфига, три цикла обновления — зависимости); боли: «p99 вырос — метрика есть, трейса нет (срезался head-сэмплингом 10%), логи ищем grep'ом по pod-имени» — корреляция руками 20 минут (инцидент-рутина); целевая архитектура: Alloy DaemonSet на ноды (scrape под-метрик через k8s-аннотации (метрики), filelog/journald логов, OTLP-приём трейсов) → Alloy-гейтвей (tail_sampling: ошибки 100%, >500 мс 100%, норма 8% (процентилям); resource-нормализация (service/env/version — единые метки везде — структура)) → Tempo/Loki/Prometheus; внедрение (месяц, по этапам): (1) Alloy-агент параллельно старым (двойной поток — сверка — Grafana-дашборды из нового пути — Grafana); (2) трейсы — сервисы на OTLP endpoint коллектора (SDK — одна env-переменная — конфигурация — 25 сервисов за 2 недели — по PR); (3) tail_sampling включён — первый эффект: инцидент «ошибки 0.3%» — все ошибочные трейсы сохранены (head-сэмплинг терял 90% — «показать пример ошибки» — было лотереей, стало — клик — Tempo); (4) связка логов (trace_id в логи приложений (логи — Loki-derived fields → Tempo → профиль окна (Pyroscope) — «метрика → трейс → логи → профиль» — клик-путь — корреляция 20 минут → 2 — главный выигрыш — три столпа+); (5) старые агенты сняты — ноды −180 МБ RAM/−0.1 CPU на ноду (ёмкость — 12 нод — заметно); (6) хранение трейсов: полный объём был бы ×12 — tail-sampling держит ×1.4 при полноте ошибок/медленных — S3-экономия; пост-эффекты: релиз-диффы профилей (Pyroscope-процесс), алерты на дропы коллектора (Alertmanager), конфиги пайплайна в git (IaC — ревью изменений телеметрии — ревью); вывод: ценность не «один агент вместо трёх» (экономия), а корреляция сигналов (инцидент-время — главная метрика observability — SRE) — пайплайн с едиными метками и умным сэмплингом — фундамент, на котором работают дашборды/алерты/расследования.
FAQ
Grafana Alloy или голый OTel Collector — что ставить? Общее: движок OTel-компонентов у обоих (receivers/processors/exporters — экосистема одна — «запирание» — миф — миграция возможна); Alloy: River-синтаксис (компонентный граф — связки явные — YAML-пайплайны против графа — дело вкуса), встроенные интеграции Grafana-стек (Loki/Tempo/Mimir/Pyroscope — scrape/journald/eBPF-профили — один агент на всё — DaemonSet-экономия), авто-обновления/Grafana Cloud-связка; голый Collector: вендор-нейтральность (экспорт в Datadog/Jaeger/ClickHouse (ClickHouse-контекст) — без Grafana-гравитации), YAML-привычнее инфраструктурщикам, чуть меньше «магии»; критерий: стек Grafana — Alloy (интеграции окупаются), стек разнородный/свой — Collector; оба деплоятся одинаково (агент+гейтвей — раздел выше — k8s — выбор синтаксиса не меняет архитектуру); «а Prometheus может сам scrape?» — может, и это ок для метрик (метрики), коллектор — когда сигналов больше одного или нужна обработка/маршрутизация.
Что такое tail sampling и зачем он нужен? Проблема сэмплинга трейсов: полный поток дорог (хранение/сеть — ×10–100 к метрикам — стоимость-контекст), head-sampling (решение на первом сервисе — «10% трейсов») режет слепo (ошибочный/медленный трейс срезается с вероятностью 90% — «показать пример ошибки» — лотерея); tail-sampling: решение после сбора трейса (гейтвей видит все спаны — политики: error → keep 100%, latency > X → keep 100%, определенный маршрут/тенант → keep, остальное → 5–10% — процентилям); цена: память гейтвея (окно трейса — минуты — буфер в RAM/диск — ёмкость — гейтвей-кластер, не одиночка), задержка экспорта (окно ожидания — секунды — приемлемо для troubleshooting-данных); требование: все спаны трейса — в один гейтвей (routing по trace_id — load-balancing exporter — иначе решение локальное — неполное); результат: ошибки/аномалии — 100% видимость при 10–20% стоимости — сценарий выше — главный аргумент коллектора в принципе.
Куда девать существующие Prometheus и Loki — заменять? Не заменять бэкенды — заменить пути доставки: Prometheus остаётся хранилищем/алертингом метрик (метрики — remote write из коллектора/Alloy — «приложение→OTLP→коллектор→Prometheus» вместо «приложение→скрейп» — pull vs push — коллектор добавляет обработку/буфер); Loki остаётся хранилищем логов (Loki — filelog-ресивер вместо promtail — один агент вместо двух — функциональность та же + OTel-метки); Jaeger/Tempo — трейсы (OTLP-экспорт — Tempo); т.е. коллектор — слой между приложениями и бэкендами (бэкенды — ваши, путь — стандартизован — «сменим Loki на ClickHouse» — меняется exporter, не приложения — архитектурная свобода); gradual-миграция из сценария (параллельный поток — сверка — переключение) — миграция-дисциплина — ноль big bang.
Как не потерять телеметрию при отказе коллектора или бэкенда? Слои: (1) persistent queue экспортёра (file_storage-расширение — очередь на диск — бэкенд лёг — телеметрия копится — recovery — отправка — часы буфера при правильном размере диска — очереди-гарантии); (2) retry-политика экспортёра (backoff — retry-паттерны — временные сбои переживаются); (3) memory_limiter (перегрузка — дроп с приоритетом — коллектор не умирает — graceful — частичная телеметрия лучше мёртвого пайплайна); (4) SDK-буфер на приложении (batch-экспорт с ретраями — короткий сбой сети — не теряется — OTel); (5) HA гейтвея (2+ реплики за LB — нода-сбой — failover-контекст — k8s-рескейл); (6) мониторинг самого пайплайна (internal-метрики: queue length/dropped/export errors — алерты (Alertmanager) — «телеметрия молчит» — само инцидент-событие — healthcheck пайплайна — healthcheck-культура); честный предел: при полном отказе всего на минуты — часть сигналов потеряется (телеметрия — не платежи (идемпотентность) — at-least-once с допустимыми потерями — приоритеты: ошибки/трейсы ценнее «фоновых» метрик — sampling-политики учитывают — SLO-контекст).
Источники: документация OpenTelemetry Collector, Grafana Alloy, collector configuration — ссылки в шапке.