awesome-everything EN
↑ Обратно к восхождению

Наблюдаемость

Трейсы и сэмплирование: cost-модель distributed tracing

Суть Как строится distributed trace, почему сэмплирование обязательно, и инженерные трейдоффы между head-based и tail-based стратегиями.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 13 min

Запрос на checkout проходит через семь сервисов перед ответом. Что-то занимает 1,2 с суммарно, но метрика говорит только «p99 вырос». Один distributed trace точно показывает, span какого сервиса потратил 1,1 с. Без сэмплирования хранить этот трейс для каждого запроса при 1000 запросах/с производит миллиард span’ов в день.

Как строится трейс

Запрос, входящий на edge, получает trace_id (128-битный, глобально уникальный). Каждый сервис, который он затрагивает, создаёт span:

  • operation_name
  • start_time, duration_ms
  • attributes (key-value пары: http.route, db.system, error.type и т.д.)
  • span_id (уникальный в пределах трейса)
  • parent_span_id (ссылка на span вызывающего сервиса)

trace_id и текущий span_id распространяются вперёд через W3C заголовок traceparent: traceparent: 00-<trace_id>-<parent_span_id>-<flags>. Collector восстанавливает дерево из span’ов; UI отображает waterfall, показывающий, где было потрачено wall-clock время.

ПолеЧто идентифицируетПример
trace_idВесь end-to-end запрос128-битный UUID, общий для всех сервисов
span_idОдна операция внутри трейса64-битный, уникальный на сервис-hop
parent_span_idКто вызвал этот spanspan_id вызывающего сервиса
traceparentW3C заголовок, распространяющий контекст00-{trace_id}-{span_id}-01

Почему сэмплирование обязательно

Хранение пропорционально числу span’ов × объёму трафика. Средний сервис эмитит 10–100 span’ов на запрос. При 1000 запросах/с:

  • 10 span’ов/запрос × 1000 запросов/с × 86 400 с = 864 М span’ов/день (минимум)
  • 100 span’ов/запрос × 1000 запросов/с × 86 400 с = 8,64 Б span’ов/день (сложный service graph)

Несжатый span — 1–5 КБ. Это терабайты trace-данных в день от одного fleet’а сервисов.

Head-based vs tail-based сэмплирование

Head-based сэмплирование принимает решение в начале трейса — хранить или нет. Если решение «отбросить», SDK не эмитит span’ы вовсе — нулевые расходы на collector, нулевые сетевые байты.

  • Типичный rate: 1–10% запросов
  • Стоимость: предсказуемая, низкий overhead
  • Слабость: равномерный random sample под-представляет редкие события (ошибки, медленные tail’ы)

Tail-based сэмплирование буферизирует span’ы до завершения трейса, затем принимает решение на основе полного контекста — была ли ошибка, превысила ли latency порог?

  • Всегда хранит 100% трейсов с ошибками и медленных tail-трейсов
  • Отбрасывает успешные быстрые трейсы по низкому base rate (0,5–5%)
  • Стоимость: каждый span всё равно проходит через collector даже если в итоге отброшен — CPU и память collector’а масштабируются с raw трафиком, не с сэмплированным объёмом

Продакшн паттерн совмещает оба: head-based 10–20% baseline для ограничения входного трафика collector’а; tail-based политики поверх для сохранения 100% ошибок и медленных трейсов из того, что поступает.

Почему это работает

Флаг sampled заголовка W3C traceparent (последний байт: 01 = сэмплирован, 00 = нет) — это то, как head-based решение распространяется вниз по стеку. Если сервис устанавливает флаг в 00, все downstream-сервисы учитывают это решение и не эмитят span’ы, сохраняя нагрузку на collector пропорциональной rate сэмплирования, а не raw трафику.

Числа трейсов и сэмплирования
Span'ов на запрос (средняя архитектура)
10–100
Span'ов в день (1k запросов/с, 10 span'ов/запрос)
~864 М
Типичный rate head-based сэмплирования
1–10%
Tail-based: сэмплирование ошибок в продакшне
100%
Tail-based: сэмплирование медленного tail (p99+)
100%
Tail-based: baseline успешных в продакшне
0,5–5%
Окно буферизации tail-sample
30–60 с на трейс
Wire overhead OTLP vs JSON
~50–70% меньше
Викторина

Сервис эмитит 100% трейсов и хранит все. Счёт вырастает в три раза за неделю. Какое наиболее распространённое продакшн-решение?

Викторина

Почему tail-based сэмплирование дороже head-based в overhead collector'а, даже если оба хранят примерно одинаковый финальный объём?

Викторина

Запрос входит в систему с traceparent, оканчивающимся на '-00' (sampled flag = 0). Downstream-сервис хочет записать свой span. Какая спецификация определяет, что нужно изменить, чтобы последующие downstream-сервисы тоже записывали span'ы?

Вспомните перед уходом
  1. 01
    Назови четыре поля, связывающие span'ы в дерево трейса, и что каждое из них идентифицирует.
  2. 02
    Почему tail-based сэмплирование дороже head-based в overhead collector'а при одинаковом финальном хранимом объёме?
  3. 03
    Сервис эмитит 10–100 span'ов на запрос при 1000 запросах/с. Оцени ежедневное число span'ов и объясни, почему 100% хранение нежизнеспособно.
Итог

Distributed trace — это дерево span’ов, соединённых trace_id и parent_span_id, распространяемых через границы сервисов через W3C заголовок traceparent. Collector восстанавливает дерево; UI показывает waterfall сервисных вызовов и их длительностей. Хранение масштабируется с числом span’ов × трафиком — средний сервис при 1000 запросах/с производит сотни миллионов span’ов в день, делая 100% retention экономически невозможным. Head-based сэмплирование дешевле всего (нулевой overhead collector’а для отброшенных трейсов), но пропускает редкие события ошибок; tail-based сэмплирование хранит 100% ошибок и медленных tail-трейсов, но буферизирует каждый span в памяти collector’а до завершения трейса, поэтому его overhead масштабируется с raw трафиком, а не с сэмплированным объёмом. Продакшн паттерн: head-based 10–20% совместно с tail-based политиками для ошибок и медленных tail’ов.

Связанные уроки
встречается в167
Продолжить восхождение ↑Join-ключи и exemplar''''ы: как три сигнала становятся компонуемыми
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.