Skip to main content
Back to course
Распределенная трассировка: от основ до production
4 / 1822%

Как устроен трейс: Traces, Spans, Context

30 минут

Цель урока

После «первого трейса за 15 минут» понять, что вы видели в UI: как устроен трейс, что значит каждая полоска и почему headers связывают все спаны в одну историю.

К концу урока вы сможете:

  • Назвать root span, его детей и самый длинный (bottleneck) span.
  • Прочитать traceparent и понять, как он связывает сервисы.
  • Отличать span-атрибуты (метаданные) от событий и статуса.

Что такое Trace

Трейс — это GPS-трекер запроса: путь через сервисы и очереди с временем в каждом шаге.

Ключевые концепции:

  • Один trace ID для всей истории запроса
  • Hierarchy: дерево от root span до вложенных операций
  • Total duration = время самого верхнего (root) спана
  • Parent-child связи через parentSpanId

Что такое Span

Span — отрезок работы с началом, концом и метаданными.

{
  "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
  "spanId": "00f067aa0ba902b7",
  "parentSpanId": "a3ce929d0e0e4736",
  "name": "GET /api/users/:id",
  "kind": "SERVER",
  "duration_ms": 150,
  "attributes": {
    "http.method": "GET",
    "http.status_code": 200,
    "user.id": 123
  },
  "events": [{ "name": "cache.miss" }],
  "status": { "code": "OK" }
}
  • parentSpanId строит дерево.
  • attributes описывают операцию (HTTP, DB, custom).
  • events — важные точки внутри спана (кэши, ретраи).
  • status — успех/ошибка.

Кinds спанов (кратко)

Типы span kinds:

  • SERVER — входящий запрос (HTTP handler, gRPC server)
  • CLIENT — исходящий запрос (HTTP client, database query)
  • PRODUCER / CONSUMER — очереди и сообщения (Kafka, RabbitMQ)
  • INTERNAL — внутренняя логика без сетевых вызовов

Эти значения помогают UI группировать и подсвечивать вызовы.


Context: как спаны связываются

Связка происходит через HTTP-заголовки W3C Trace Context. Главный — traceparent.

Формат:

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
             ││  │                                │                ││
             ││  └─ trace ID (32 hex)             │                ││
             │└─ version (00)                     │                ││
             │                                    └─ parent span ID (16 hex)
             └─ flags (01 = sampled)

Как это работает:

  1. Входящий запрос: Сервис читает traceparent, создает span с тем же trace ID и parentSpanId из заголовка
  2. Исходящий запрос: Сервис пишет новый traceparent с собственным spanId в parentSpanId для следующего сервиса

tracestate — доп. заголовок с вендорными данными (sampling priority, debuggers). Его можно игнорировать на старте.


Мини-практика (на основе HotROD)

  1. Откройте свежий трейс HotROD из прошлого урока.
  2. Найдите root span (обычно frontend).
  3. Отметьте самый длинный span — в HotROD это часто route или database.
  4. В заголовках HTTP (клик по спану в UI) найдите traceparent — убедитесь, что traceId совпадает у всех спанов.

Чеклист понимания

  • Понимаю разницу между trace и span.
  • Могу назвать root span, его детей и самый длинный span.
  • Знаю, как traceparent связывает спаны между сервисами.
  • Отличаю атрибуты спана от событий и статуса.

Что дальше

В следующем уроке добавим первую инструментацию простого приложения и посмотрим, как спаны появляются в трейсе после пары строк кода.