Прямой ответ
Распределённая трассировка фиксирует путь запроса через сервисы, поэтому задержка либо ошибка локализуется на конкретном участке, а не определяется по общему времени.
| Понятие | Что описывает |
|---|---|
| Трейс | Полный путь одного запроса |
| Спан | Отдельная операция внутри запроса |
| Идентификатор трейса | Общий признак всех спанов запроса |
| Родительский спан | Спан, породивший текущий |
from opentelemetry import trace
tracer = trace.get_tracer("app")
with tracer.start_as_current_span("handle-order") as span:
span.set_attribute("order.id", order_id)
with tracer.start_as_current_span("db-query"):
rows = fetch(order_id)
Спан содержит имя операции, время начала и длительность, поэтому дерево вызовов показывает, какая операция занимает основную долю времени. О распространении контекста — в статье про контекст запроса.
Распространение контекста и родительские связи
Контекст трейса передаётся между сервисами, поэтому спаны разных процессов объединяются в одно дерево.
Передача контекста. Идентификатор трейса и идентификатор родительского спана передаются в заголовках запроса, поэтому принимающий сервис продолжает тот же трейс.
Родительская связь. Спан, созданный внутри другого спана, ссылается на родителя, поэтому порядок вложенности отражает последовательность вызовов.
Параллельные ветви. Спаны, созданные от одного родителя, выполняются параллельно либо последовательно, поэтому дерево показывает структуру обработки запроса.
Практическое следствие: без передачи контекста спаны разных сервисов образуют отдельные трейсы, поэтому путь запроса не виден целиком.
Отдельный аспект — охват инструментируемых участков. Спан создаётся для операции, длительность которой требуется измерить, поэтому создание спана для каждой строки кода не имеет смысла.
Три признака некорректной трассировки.
Отсутствие передачи контекста. Спаны разных сервисов не объединяются, поэтому путь запроса не восстанавливается.
Слишком мелкие спаны. Накладные расходы на создание спана превышают длительность операции, поэтому дерево перегружено.
Отсутствие атрибутов. Спан без признаков не позволяет определить, к какому объекту относится операция.
О поиске узких мест по трейсу — в статье про диагностику по трейсам; о месте трассировки среди сигналов — в статье про три сигнала.
Практика: настройка распределённой трассировки
1. Создавайте спаны для значимых операций. Длительность операции измеряется, поэтому спан создаётся там, где требуется измерение.
2. Передавайте контекст между сервисами. Идентификатор трейса передаётся в заголовках, поэтому спаны объединяются в дерево.
3. Добавляйте атрибуты к спанам. Признаки объекта позволяют определить, к какому запросу относится операция.
4. Соблюдайте родительские связи. Спан, созданный внутри другого, ссылается на родителя, поэтому структура вызовов отражается.
5. Не создавайте спаны для тривиальных операций. Накладные расходы превышают длительность, поэтому дерево перегружается.
6. Проверяйте полноту трейса. Отсутствие спана на участке пути указывает на отсутствие передачи контекста.
7. Фиксируйте ошибки в спане. Признак ошибки в спане позволяет найти сбойный участок без просмотра логов.
Рекомендации:
- Различайте трейс и спан. Трейс описывает путь запроса, спан — отдельную операцию внутри пути.
- Учитывайте накладные расходы создания спана. Спан для операции короче накладных расходов не даёт полезной информации.
- Проверяйте передачу контекста через промежуточные узлы. Прокси может не передавать заголовки, поэтому контекст теряется.
- Фиксируйте длительность значимых участков. Измерение позволяет определить долю времени, занимаемую операцией.
- Пересматриваем охват при изменении структуры сервисов. Новый сервис требует передачи контекста для включения в трейс.
Практический сценарий: задержка запроса не локализовалась
Контекст: время выполнения запроса превышало ожидаемое, при этом метрики не показывали деградации отдельного сервиса.
- Диагностика. Трейс запроса показал дерево спанов, в котором один участок занимал основную долю времени. Участок соответствовал обращению к внешнему сервису, длительность которого не контролировалась метриками собственного приложения.
- Причина. Задержка возникала на внешнем обращении, которое не покрывалось метриками сервиса. Общее время запроса росло, при этом метрики собственного приложения оставались в норме.
- Действия. (а) Проверили полноту трейса и убедились, что контекст передаётся через все сервисы; (б) добавили атрибуты к спану внешнего обращения, чтобы определять целевой ресурс; (в) установили таймаут внешнего обращения, чтобы задержка не переносилась на весь запрос; (г) добавили метрику длительности внешнего обращения как контролируемую величину; (д) проверили дерево трейса после изменения и убедились в сокращении общей длительности.
- Результат. Задержка локализуется по трейсу, а таймаут ограничивает влияние внешнего обращения.
Вывод: метрики сервиса не показывают задержку на внешнем обращении, поэтому общая деградация не локализуется. Трассировка показывает дерево операций, поэтому участок с основной долей времени определяется по длительности спанов.
FAQ
Что такое спан? Отдельная операция внутри запроса с именем, временем начала и длительностью. Спаны образуют дерево по родительским связям.
Как спаны разных сервисов объединяются в трейс? Через передачу контекста в заголовках запроса. Принимающий сервис продолжает тот же трейс, поэтому спаны связываются.
Зачем нужны атрибуты спана? Признаки объекта позволяют определить, к какому запросу либо ресурсу относится операция. Спан без атрибутов не даёт контекста.
Нужно ли создавать спан для каждой операции? Нет, спан создаётся для значимых операций, длительность которых требуется измерить. Накладные расходы на тривиальные операции превышают пользу.
Источники: OpenTelemetry traces, W3C Trace Context, OpenTelemetry Python — ссылки в шапке.