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

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

Head sampling и tail sampling: кто решает, какие трейсы выживают

Суть Head sampling дёшев, но слеп: решение принимается до знания исхода. Tail sampling видит весь трейс, ловя ошибки и медленные запросы ценой RAM collector''''а и дисциплины роутинга.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 13 min

Сервис обрабатывает 10 000 запросов в секунду. Хранить каждый трейс непомерно дорого. Но при случайном sampling в 1% один медленный запрос, вызвавший жалобу клиента, с вероятностью 99% будет тихо выброшен.

Head-based sampling

Решение keep/drop принимается на старте трейса — кодируется в бите 01 (sampled) trace-flags заголовка traceparent. Решение пропагируется на все downstream-сервисы, которые уважают его по умолчанию.

Типовые стратегии:

  • Вероятностная: хранить N% трейсов (1–5% типично). Простая, предсказуемая, масштабируется линейно с трафиком.
  • Rate-limiting: хранить не более K трейсов в секунду независимо от объёма трафика.

Стоимость: дёшево — решение принимается один раз на root span, до выполнения какой-либо работы. Несэмплированные запросы не генерируют span’ов вообще, экономя CPU, сеть и хранение.

Недостаток: решение слепо к исходу. Медленный или error-запрос, попавший в несэмплированные 99%, невидим в tracing-backend. Если инцидент затрагивает 0.5% трафика, а sampling 1% — сохранишь примерно половину инцидентных трейсов; но можешь не сохранить ни одного, если инцидент кратковременный.

Sampled-флаг: когда флаг 01, downstream-сервисы записывают и экспортируют span’ы. Когда 00, OTel SDK создают span’ы внутри, но по умолчанию не экспортируют. Это consistent sampling: либо весь трейс хранится, либо ничего — никогда фрагмент. Downstream-сервис может переопределить входящий флаг (например, всегда сэмплировать свои ошибки), но частичные переопределения дают фрагментарные трейсы, почти бесполезные для отладки.

Tail-based sampling

OTel Collector буферизует все span’ы для trace-id в течение настраиваемого decision-окна (30с–5мин), затем решает, хранить ли трейс, по policy:

  • Есть ошибка → хранить 100%.
  • Duration > порог → хранить 100%.
  • Конкретный атрибут (например user.tier=premium) → хранить 100%.
  • Вероятностный top-up → хранить 1% остального для базовой видимости.

Преимущества:

  • Ловит каждый error-трейс даже при 0.1% трафика.
  • Ловит каждый медленный трейс выше latency-порога.
  • Даёт избирательность, делающую tail sampling доминирующим паттерном у high-traffic-сервисов.

Стоимость: collector обязан держать все span’ы каждого трейса в RAM до decision-time.

Модель памяти: active_traces × avg_spans_per_trace × bytes_per_span. При 50 000 in-flight трейсов × 100 span’ов × 1 KB на span = 5 GB RAM. Decision-окно напрямую управляет RAM-footprint’ом.

Требование load-balancing exporter: с несколькими репликами collector’а случайное распределение span’ов разбрасывает span’ы одного трейса по разным instance’ам. Каждый видит только фрагменты и не может принять корректное решение. Решение — load-balancing exporter, хэширующий по trace-id и направляющий все span’ы одного трейса на один и тот же collector instance. Это обязательно для корректной работы tail sampling.

ПараметрHead samplingTail sampling
Момент решенияНа старте трейса (head)После завершения всех span’ов (tail)
Видит исход?НетДа (ошибка, latency, атрибуты)
RAM collector’аМинимальнаяПропорционально active_traces × span’ы × размер span’а
Требование роутингаНет (stateless)Load-balancing exporter (хэш по trace-id)
Пропускает error-трейсы?Да (с частотой 1 − sample%)Нет (если error policy = 100%)

Гибридный паттерн (доминирует в production)

Head-sample на 100% (каждый запрос входит в pipeline), затем tail-sample по policy:

  • Error-трейсы → хранить 100%.
  • Latency > 99-й перцентиль → хранить 100%.
  • Всё остальное → 1% вероятностно.

Это даёт volume-контроль head sampling и избирательность tail sampling, за счёт одной дополнительной инфры: tier tail-sampling Collector с load-balancing exporter и достаточной RAM.

При 10k req/s с 30с decision-окном, 10 span’ами/трейс, 1 KB/span: 10 000 × 30 × 10 × 1 024 B ≈ 3 GB RAM collector’а. Реализуемо с 4–8 репликами collector’а.

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

Гибридный паттерн — это почему «нужно хранить все error-трейсы» и «нельзя хранить всё» не взаимоисключающие. Head sampling пропускает каждый запрос без коммита хранения; tail-sampling tier затем применяет policy 100% для ошибок. Инженеры, пытающиеся решить это только head sampling, либо хранят всё (дорого), либо пропускают ошибки (ненадёжно). Двухуровневый дизайн разрешает оба ограничения.

Референсные числа по стоимости sampling
Типичная частота head sampling
0.5–5% трейсов
Типичное decision-окно tail sampling
30с–5 мин
RAM tail-sampler при 50k трейсов × 100 span × 1 KB
~5 GB
RAM tail-sampler при 10k req/s, 30с окно, 10 span, 1 KB
~3 GB
Load-balancing exporter: ключ роутинга
хэш по trace-id
Consistent sampling: трейс хранится/дропается
100% или 0% — никогда фрагмент
Викторина

Команда выбирает tail-based sampling, чтобы хранить все error-трейсы. Какой операционный подвох нужно учесть?

Викторина

traceparent приходит с sampled-флагом `00`. Что должен делать принимающий сервис по умолчанию?

Викторина

Tail-sampling Collector OOM'ит каждые несколько часов. Метрики показывают стабильное число трейсов, но растущее число span'ов на трейс. Вероятная причина?

Вспомните перед уходом
  1. 01
    Почему head sampling пропускает error-трейсы и какова частота пропуска?
  2. 02
    Объясни load-balancing exporter и почему tail sampling ломается без него.
  3. 03
    Опиши гибридный паттерн head-100% + tail-policy и когда действует каждый уровень.
Итог

Head sampling принимает решение keep/drop на старте трейса, используя sampled-флаг traceparent, пропагируя решение на все downstream-сервисы. Дёшево — несэмплированные запросы не генерируют span’ов вообще — но слепо к исходам: 1% head rate дропает 99% error-трейсов вместе с 99% нормальных. Tail sampling буферизует все span’ы в OTel Collector до закрытия decision-окна (30с–5мин), затем применяет policy: хранить все ошибки, хранить все медленные, хранить 1% baseline. Стоимость — RAM collector’а (active_traces × span’ы/трейс × байт/span) и обязательный load-balancing exporter, маршрутизирующий все span’ы одного трейса на один collector instance. Гибридный head-100% + tail-policy — production-стандарт: head при 100% подаёт всё в pipeline; tail tier решает, что персистировать.

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

Trademarks belong to their respective owners. Editorial reference only.