Прямой ответ
Семплирование — сохранение части трейсов вместо всех. При высокой нагрузке полный сбор трейсов стоит дороже, чем польза от них, поэтому сохраняется доля. Ключевой вопрос — в какой момент принимается решение об отборе, и от этого зависит, попадут ли в хранилище интересные случаи.
Head sampling — решение принимается в начале трейса, до того как известно, чем он завершится:
| Head sampling | Tail sampling | |
|---|---|---|
| Момент решения | Начало трейса | После завершения трейса |
| Критерий | Случайная доля | Свойства завершённого трейса |
| Требует буферизации | Нет | Да |
| Сохраняет трейсы с ошибками | Случайно | Гарантированно |
| Стоимость инфраструктуры | Ниже | Выше |
Head sampling реализуется на стороне приложения и не требует дополнительного компонента:
# OpenTelemetry: отбирается 1 трейс из 100
sampler = TraceIdRatioBased(0.01)
Ограничение head sampling: трейс с ошибкой сохраняется с той же вероятностью, что и успешный. При доле 1 процент и частоте ошибок 0,1 процента в хранилище окажется примерно один из ста ошибочных трейсов — ровно тогда, когда он нужен для разбора.
Tail sampling — решение принимается после завершения трейса, когда известны его длительность, наличие ошибок и пройденные сервисы:
# политики отбора в коллекторе
processors:
tail_sampling:
policies:
- name: errors-always
type: status_code
status_code: {status_codes: [ERROR]}
- name: slow-traces
type: latency
latency: {threshold_ms: 2000}
- name: sample-rest
type: probabilistic
probabilistic: {sampling_percentage: 5}
Такая конфигурация сохраняет все трейсы с ошибками, все медленные трейсы и 5 процентов остальных. Это решает главную проблему head sampling: интересные случаи сохраняются гарантированно.
Цена tail sampling — буферизация. Коллектор должен хранить спаны трейса до его завершения, чтобы принять решение. При высокой нагрузке это требует памяти и ограничивает время ожидания; о сборе телеметрии — в статье про трейсинг распределённых транзакций.
Практическое правило: head sampling подходит при ограниченном бюджете и низкой частоте ошибок. Tail sampling оправдан, когда разбор инцидентов требует конкретных трейсов с ошибками, а не случайной выборки; о метриках — в статье про инструментирование приложения.
Стоимость хранения и выбор доли
Доля отбора напрямую определяет объём данных, а значит и счёт за хранилище. Расчёт помогает выбрать значение осознанно, а не наугад.
Оценка объёма строится от числа запросов:
запросов в сутки × спанов на запрос × размер спана × доля отбора = объём в сутки
Для сервиса с миллионом запросов в сутки, пятью спанами на запрос и размером спана 1 килобайт полный сбор даёт около 5 гигабайт в сутки. Доля 10 процентов снижает объём до 500 мегабайт, но вместе с ним снижает вероятность сохранения редкого события.
Tail sampling меняет экономику: объём растёт за счёт сохранения всех ошибочных трейсов, но снижается за счёт меньшей доли случайного отбора. Итоговый объём часто сопоставим с head sampling при существенно большей полезности данных.
Три практических правила выбора доли:
Ориентируйтесь на редкость события. Если интересующее событие происходит раз в тысяче запросов, доля 1 процент сохраняет одно событие из десяти.
Разделяйте долю по типам операций. Редкие операции сохраняются полностью, массовые — с малой долей. Это требует tail sampling, поскольку решение принимается по завершении.
Пересматривайте долю при изменении нагрузки. Настройка, выбранная для тысячи запросов в секунду, даёт избыточный объём при десяти тысячах.
Практика: настройка семплирования
1. Начните с head sampling. Доля 10 процентов даёт достаточно данных для анализа типичного поведения и не требует дополнительной инфраструктуры.
2. Переходите к tail при частых разборах инцидентов. Если разбор регулярно упирается в отсутствие трейса с ошибкой, случайный отбор себя исчерпал.
3. Сохраняйте все трейсы с ошибками. Правило «ошибки — всегда» даёт наибольшую пользу на единицу стоимости хранения.
4. Сохраняйте медленные трейсы. Порог выбирается по целевой задержке: если SLO составляет 500 миллисекунд, сохранять стоит трейсы дольше 1000; о расчёте — в статье про процентили.
5. Сохраняйте трейсы целиком, а не отдельные спаны. Частичный трейс не показывает путь запроса и бесполезен для анализа.
6. Согласуйте долю между сервисами. Разная доля в разных сервисах приводит к разрывам в трейсах: решение принимается в первом сервисе и передаётся дальше.
7. Контролируйте стоимость хранения. Доля отбора напрямую определяет объём данных; о запросах к накопленному — в статье про LogQL.
8. Проверяйте, что нужный трейс сохранился. После изменения политик убедитесь, что ошибочные запросы попадают в хранилище.
Рекомендации:
- Не отбирайте трейсы по идентификатору пользователя. Это приводит к систематическому смещению выборки.
- Разделяйте доли для разработки и продуктивной среды. В разработке отбор обычно не нужен, поскольку нагрузка мала.
- Учитывайте время буферизации в tail sampling. Трейс, не завершившийся за отведённое окно, может быть отброшен без решения.
- Сохраняйте трейсы с редкими операциями. Операция, выполняемая раз в сутки, при доле 1 процент может не попасть в хранилище ни разу за месяц.
- Пересматривайте долю при росте нагрузки. Настройка, подходящая для тысячи запросов в секунду, избыточна при десяти тысячах.
Практический сценарий: невозможность разобрать ошибку из-за случайного отбора
Контекст: сервис работал с head sampling на 1 процент. При разборе периодических ошибок оплаты нужный трейс отсутствовал в хранилище в четырёх случаях из пяти.
- Диагностика. Частота ошибок составляла 0,2 процента запросов. При доле отбора 1 процент вероятность сохранения ошибочного трейса была такой же, как для успешного, поэтому большинство инцидентов оставалось без данных.
- Причина. Семплирование настраивалось для снижения стоимости хранения, и критерий отбора не учитывал ценность трейса. Все трейсы считались одинаково полезными.
- Действия. (а) Добавили коллектор с tail sampling; (б) настроили три политики: все трейсы с ошибками, все трейсы дольше двух секунд, 3 процента остальных; (в) увеличили объём хранилища, поскольку доля сохраняемых трейсов с ошибками выросла; (г) уменьшили долю случайного отбора с 10 до 3 процентов, чтобы компенсировать рост объёма; (д) проверили на тестовой нагрузке, что ошибочные трейсы сохраняются.
- Результат. Все ошибочные трейсы стали доступны для разбора, а общий объём хранилища вырос на 20 процентов вместо ожидаемого кратного увеличения.
Вывод: доля отбора определяет не только стоимость, но и возможность разбора инцидентов. Head sampling экономит ресурсы, но теряет редкие события; tail sampling сохраняет ценные трейсы гарантированно ценой буферизации и дополнительной инфраструктуры.
FAQ
Какую долю отбора выбрать? Начните с 10 процентов и снижайте при росте нагрузки. Ошибочные и медленные трейсы сохраняйте полностью независимо от доли.
Можно ли использовать оба подхода одновременно? Да. Head sampling снижает объём данных на стороне приложения, а tail sampling в коллекторе отбирает ценные трейсы из оставшихся.
Почему в трейсе не хватает спанов? Вероятная причина — разная доля отбора в разных сервисах. Решение должно приниматься в первом сервисе и передаваться по цепочке.
Что дороже: head или tail sampling? Tail sampling требует коллектора с буферизацией, но может снизить объём хранилища за счёт сохранения только ценных трейсов. Общая стоимость зависит от политик отбора.
Источники: OpenTelemetry docs (Sampling, Tail Sampling), Grafana Tempo docs — ссылки в шапке.