5. Jaeger и альтернативы
Хранение и визуализация распределенных трейсов
«Лучший способ предсказать будущее — воплотить его в коде».
— Алан Кэй
В предыдущих статьях мы научились генерировать спаны в Go-сервисах, наполнять их семантическими атрибутами и пробрасывать W3C-контекст через границы сетевых протоколов. Теперь перед нами встает фундаментальная инфраструктурная задача: где хранить миллиарды спанов в сутки и через какой инструмент визуализировать сложные водопадные диаграммы (Waterfall Diagrams) запросов?
На протяжении многих лет золотым стандартом распределенной трассировки в open-source экосистеме оставался Jaeger. Однако взрывной рост объемов данных и популяризация объектных хранилищ породили новые архитектурные решения — в первую очередь Grafana Tempo.
Разберем, как устроены эти бэкенды под капотом, сколько стоит их эксплуатация и как правильно интегрировать их с приложениями на Go.
Визуализация мира трейсов
Главная ценность систем трассировки — предоставить инженеру интуитивную визуальную шкалу времени (Timeline / Waterfall). Когда в одном трейсе участвуют 50 спанов от 12 сервисов, пользовательский интерфейс должен мгновенно подсвечивать:
- Критический путь (Critical Path): последовательность операций, определяющая общее время ответа.
- Параллельные вызовы (Concurrent RPCs): ветвления, где запросы выполнялись одновременно.
- Точки сбоев: покрасневшие спаны с подробными стектрейсами ошибок.
Jaeger: Классика Open Source
Jaeger — это распределенная система трассировки, изначально разработанная в недрах компании Uber для мониторинга тысяч микросервисов, а затем переданная в CNCF (где стала выпускником высшего уровня). Jaeger написан на Go, что делает его архитектурно близким и понятным нашему сообществу.
Архитектура Jaeger
Jaeger построен на микросервисной архитектуре, что позволяет ему масштабироваться горизонтально.
flowchart LR
A["Go App"] -->|"OTLP/UDP"| B["otel-collector"]
B -->|"gRPC"| C["Jaeger Collector"]
subgraph Storage ["Storage Layer"]
D["Elasticsearch<br>или Cassandra"]
end
C -->|"Write"| D
D -->|"Read"| E["Jaeger Query<br>UI"]
F["User"] --> E
style A fill:#1e293b,stroke:#38bdf8,stroke-width:2px,color:#fff
style B fill:#312e81,stroke:#818cf8,stroke-width:2px,color:#fff
style C fill:#065f46,stroke:#10b981,color:#fff
style Storage fill:#0f172a,stroke:#475569,color:#fff
style E fill:#78350f,stroke:#f59e0b,color:#fff
Компоненты Jaeger:
- Collector: Принимает спаны от приложения (или от OTel Collector), валидирует их, индексирует и пишет в базу. Stateless, можно масштабировать горизонтально за балансировщиком нагрузки.
- Query: Сервис, обслуживающий UI и API для поиска трейсов.
- Agent (Deprecated): Раньше использовался как sidecar для буферизации данных по UDP. Сейчас команда Jaeger рекомендует использовать OpenTelemetry Collector вместо Agent.
Альтернативы: Grafana Tempo
Появление Grafana Tempo изменило правила игры. Tempo не индексирует содержимое трейсов (теги, названия операций). Он индексирует только Trace ID.
Философия: Trace ID Lookup
Как мы обычно ищем трейсы?
- Мы видим ошибку в Logs (Loki).
- В логе есть
trace_id. - Мы копируем этот ID и ищем в трейсинге.
Tempo оптимизирован именно под этот сценарий. Так как он не строит сложных индексов, стоимость хранения трейсов в Tempo в 10-100 раз ниже, чем в Jaeger с Elasticsearch. Данные сжимаются и складываются напрямую в дешевое объектное хранилище (S3/GCS/MinIO).
TraceQL
Tempo представил TraceQL — язык запросов для поиска трейсов, похожий на LogQL.
Пример: {} | span.http.status_code = 500.
Это позволяет искать трейсы, даже если вы не знаете Trace ID заранее, но поиск происходит медленнее, чем по индексу. Движок потоково вычитывает сжатые блоки из S3 параллельными воркерами.
Сравнение систем
| Система | Стратегия хранения | Сложность поддержки | Стоимость | Best for |
|---|---|---|---|---|
| Jaeger + ES | Индексация всех полей | Высокая (Java/ES expertise) | Высокая | Глубокий аналитический поиск, аудит. |
| Jaeger + Cassandra | Ограниченная индексация | Высокая | Средняя | Экстремальная нагрузка (Uber-scale). |
| Grafana Tempo | No-Index (Object Storage) | Низкая | Очень низкая | Kubernetes, интеграция с Loki/Grafana. |
| Zipkin | Классический старый стандарт | Средняя | Средняя | Legacy системы, простые проекты. |
Интеграция с Go: Jaeger vs OTel
Исторически Jaeger имел свои клиентские библиотеки (jaeger-client-go). Это путь в никуда.
Вам не нужно менять код, чтобы сменить бэкенд с Jaeger на Tempo. Вы меняете только конфигурацию Exporter'а в OTel Collector.
Пример конфигурации OTel Collector (отправка в Jaeger):
# otel-collector-config.yaml
exporters:
otlp:
endpoint: jaeger-collector:4317 # Стандартный gRPC порт Jaeger
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
exporters: [otlp]
Итог
- Jaeger — зрелый, мощный инструмент. Идеален, если вам нужен сложный поиск по атрибутам трейсов. Сложен в эксплуатации (особенно с Elasticsearch).
- Grafana Tempo — современный стандарт для Kubernetes. Дешевле, проще, интегрирован в экосистему Grafana (Loki + Tempo + Mimir).
- OpenTelemetry SDK — единственно верный выбор для Go-приложения. Не завязывайтесь на проприетарные агенты.
Раздел Трейсинга завершен. Мы переходим к практике объединения всех знаний. В следующей статье мы разберем, как связать логи, метрики и трейсы через Correlation ID: 1. Correlation ID.