Распределённый трейс показывает путь одного запроса через все сервисы: кто кого вызвал, сколько длился каждый шаг, где случилась ошибка. Метрика скажет «p99 оформления заказа вырос до 3 секунд», трейс покажет «2.6 секунды из них ждали ответа от сервиса скидок».
Модель
- Trace: всё дерево работы по одному запросу, у него
trace_id(16 байт, 32 hex-символа). - Span: одна операция внутри трейса: входящий HTTP-запрос, запрос в базу, вызов другого сервиса. У спана свой
span_id(8 байт), ссылка на родителя, начало и конец, имя, статус, атрибуты (http.request.method,db.system), события (например, исключение). - Kind: SERVER (обработка входящего), CLIENT (исходящий вызов), PRODUCER и CONSUMER (сообщения), INTERNAL.
- Resource: кто прислал данные:
service.name, версия, окружение, под.service.nameобязателен, без него все спаны окажутся в «unknown_service».
Распространение контекста
Чтобы спаны разных сервисов собрались в одно дерево, контекст передаётся вместе с вызовом. Стандарт W3C Trace Context, заголовок:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
версия-trace_id (32 hex)-родительский span_id (16 hex)-флаги
Флаг 01 означает «трейс сэмплирован, записывайте». Рядом бывают tracestate (данные конкретных вендоров) и baggage (пары ключ-значение, которые едут через всю цепочку, например tenant). В очередях контекст кладут в заголовки сообщения. Если хотя бы один сервис в цепочке не пробрасывает заголовок, трейс рвётся на две части.
OpenTelemetry
OpenTelemetry (OTel) открытый стандарт CNCF для сбора трейсов, метрик и логов, не привязанный к вендору.
- API и SDK для языков: создать спан, добавить атрибуты, настроить экспорт.
- Авто-инструментирование: Java-агент,
opentelemetry-instrumentдля Python, пакеты для Node.js и .NET оборачивают HTTP-клиенты, серверы, драйверы баз без правки кода. Есть и инструментирование через eBPF без изменения процесса. - Semantic conventions: единые имена атрибутов (
http.response.status_code,db.system,server.address), чтобы бэкенды понимали данные одинаково. - OTLP: протокол передачи, по умолчанию порт 4317 для gRPC и 4318 для HTTP.
- Collector: отдельный процесс-конвейер: receivers (OTLP, Jaeger, Prometheus) → processors (batch, memory_limiter, фильтрация, добавление атрибутов, сэмплирование) → exporters (Tempo, Jaeger, вендоры). Ставится агентом на узел и шлюзом перед хранилищем.
receivers:
otlp:
protocols: { grpc: {}, http: {} }
processors:
memory_limiter: { check_interval: 1s, limit_percentage: 80 }
batch: {}
exporters:
otlp/tempo:
endpoint: tempo:4317
tls: { insecure: true }
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp/tempo]
Сэмплирование
Хранить все трейсы высоконагруженного сервиса дорого. Варианты:
- Head-based: решение принимается в начале трейса (например, 5% по
trace_id) и передаётся флагом дальше, все сервисы согласны. Дёшево, но решение принимается до того, как известно, был ли запрос медленным или ошибочным. - Tail-based: Collector ждёт окончания трейса и решает по его содержимому: сохранить все ошибки, все медленнее 2 секунд и 1% остальных. Точнее, но все спаны одного трейса должны попасть в один экземпляр Collector (балансировка по
trace_id), и нужно держать трейсы в памяти.
Стандартный сэмплер SDK ParentBased(TraceIdRatioBased): уважает решение родителя, а корневые спаны сэмплирует по доле.
Бэкенды
- Jaeger: классический открытый бэкенд, вторая версия построена на OpenTelemetry Collector.
- Grafana Tempo: хранит трейсы в объектном хранилище, ищет по TraceQL, дешёв на больших объёмах.
- Zipkin, коммерческие APM.
Связь с метриками и логами
- Exemplars: к точке гистограммы задержки прикрепляется
trace_idконкретного запроса. На графике p99 видно точку, клик ведёт в трейс. - trace_id в логах: из спана открываются логи именно этого запроса.
- Метрики из спанов: Collector или Tempo могут строить RED-метрики по спанам (span metrics, service graph).
Частые ошибки
- Не пробрасывают контекст через очередь или самописный HTTP-клиент: трейсы рвутся.
- Нет
service.name. - Атрибуты с персональными данными и токенами.
- Сэмплирование 100% в проде без оценки стоимости, или 0.1% без tail-sampling, и нужных трейсов ошибок нет.
- Имена спанов с ID (
GET /users/123): высокая кардинальность в бэкенде. Нужен шаблон маршрута.
Что спросят на собесе
- Что такое trace и span, как связываются спаны разных сервисов.
- Что в заголовке
traceparent. - Head-based против tail-based сэмплирования.
- Из чего состоит OpenTelemetry и зачем Collector.
- Как связать трейсы с метриками и логами.