Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Контекст запроса: распространение через сервисы

Контекст запроса: передача идентификаторов и атрибутов

Распространение контекста запроса: заголовки передачи, сохранение признаков, потеря контекста на промежуточных узлах и проверка полноты.

Прямой ответ

Контекст запроса передаётся в заголовках вызова, поэтому спаны и признаки разных сервисов объединяются в один путь вместо набора независимых участков.

Элемент Назначение
Заголовок передачи Переносит идентификаторы между сервисами
Сохранение контекста Принимающий сервис продолжает путь
Исходящая инъекция Контекст включается в вызов следующему сервису
Потеря контекста Промежуточный узел не передаёт заголовки
from opentelemetry import context, propagate

headers = {}
propagate.inject(headers)
response = httpx.get(url, headers=headers)

ctx = propagate.extract(carrier=request.headers)
token = context.attach(ctx)

Инъекция контекста в исходящий вызов и извлечение из входящего обеспечивают непрерывность пути. Об основах трассировки — в статье про распределённую трассировку.

Сохранение и передача контекста

Контекст извлекается из входящего запроса и используется для продолжения пути, поэтому новый путь не создаётся.

Извлечение из входящего. Заголовки входящего запроса разбираются, поэтому идентификаторы пути восстанавливаются и используются дальше.

Инъекция в исходящий. Контекст включается в заголовки исходящего вызова, поэтому принимающий сервис продолжает путь.

Привязка к текущей операции. Контекст привязывается к текущему потоку либо задаче, поэтому спаны, созданные внутри, относятся к тому же пути.

Практическое следствие: извлечение контекста без инъекции в исходящие вызовы прерывает путь, поэтому часть сервисов образует отдельные пути.

Отдельный аспект — потеря контекста на промежуточных узлах. Прокси либо шлюз может не передавать заголовки, поэтому контекст теряется между сервисами.

Три признака некорректного распространения.

Отсутствие инъекции в исходящие вызовы. Контекст не доходит до следующего сервиса, поэтому путь прерывается.

Отсутствие извлечения из входящих. Контекст входящего запроса не используется, поэтому создаётся новый путь.

Потеря на промежуточном узле. Прокси не передаёт заголовки, поэтому контекст теряется между сервисами.

О признаках обращения в логах — в статье про сквозной идентификатор; о связи контекста с сигналами — в статье про связь метрик и трейсов.

Асинхронные участки и привязка контекста

Передача контекста между асинхронными задачами требует явной привязки, поэтому контекст не теряется при переключении задач.

Привязка к задаче. Контекст привязывается к текущей задаче, поэтому спаны, созданные внутри, относятся к тому же пути.

Передача между задачами. Контекст передаётся явно при создании задачи, поэтому путь продолжается без разрыва.

Отсутствие привязки. Задача без привязки контекста создаёт новый путь, поэтому связь с предыдущим участком теряется.

Практическое следствие: асинхронный участок без явной привязки контекста разрывает путь, поэтому часть сервисов не объединяется в дерево.

Практика: настройка распространения контекста

1. Извлекайте контекст из входящего запроса. Заголовки разбираются, поэтому путь продолжается, а не начинается заново.

2. Инжектируйте контекст в исходящие вызовы. Контекст включается в заголовки, поэтому следующий сервис продолжает путь.

3. Привязывайте контекст к текущей операции. Спаны, созданные внутри, относятся к тому же пути.

4. Проверяйте передачу через промежуточные узлы. Прокси может не передавать заголовки, поэтому контекст теряется.

5. Используйте стандартный формат заголовков. Единый формат обеспечивает совместимость между сервисами и инструментами.

6. Проверяйте полноту пути. Отсутствие спана на участке указывает на потерю контекста.

7. Фиксируйте потерю контекста в записи. Признак потери позволяет определить узел, на котором прерывается путь.

Рекомендации:

  1. Не создавайте новый путь при наличии входящего контекста. Новый путь разрывает связь, поэтому часть сервисов не объединяется.
  2. Учитывайте асинхронные участки. Передача контекста между задачами требует явной привязки, поэтому контекст не теряется.
  3. Сопоставляйте контекст с признаками обращения. Связь контекста с идентификатором обращения позволяет перейти от записи к дереву.
  4. Фиксируйте длительность участков пути. Измерение позволяет определить долю времени, занимаемую участком.
  5. Пересматриваем распространение при добавлении сервисов. Новый сервис требует извлечения и инъекции контекста.

Практический сценарий: путь запроса разорвался на промежуточном узле

Контекст: спаны части сервисов не объединялись в один путь, поэтому полная картина обработки не восстанавливалась.

  1. Диагностика. Проверка показала, что прокси между двумя сервисами не передавал заголовки контекста. Принимающий сервис не получал заголовки, поэтому создавал новый путь вместо продолжения существующего.
  2. Причина. Промежуточный узел не передавал заголовки контекста, поэтому связь между участками пути терялась.
  3. Действия. (а) Настроили передачу заголовков контекста на прокси; (б) проверили, что принимающий сервис извлекает контекст, а не создаёт новый путь; (в) проверили инъекцию контекста в исходящие вызовы каждого сервиса; (г) проверили дерево пути и убедились в объединении спанов всех сервисов; (д) добавили запись о потере контекста, чтобы определять узел прерывания.
  4. Результат. Спаны всех сервисов объединяются в один путь, поэтому обработка видна целиком.

Вывод: промежуточный узел, не передающий заголовки контекста, разрывает путь между сервисами. Настройка передачи заголовков и проверка извлечения контекста на принимающей стороне восстанавливают непрерывность пути.

Практический сценарий: путь запроса разорвался на промежуточном узле

Контекст: спаны части сервисов не объединялись в один путь, поэтому полная картина обработки не восстанавливалась.

  1. Диагностика. Проверка показала, что прокси между двумя сервисами не передавал заголовки контекста. Принимающий сервис не получал заголовки, поэтому создавал новый путь вместо продолжения существующего.
  2. Причина. Промежуточный узел не передавал заголовки контекста, поэтому связь между участками пути терялась.
  3. Действия. (а) Настроили передачу заголовков контекста на прокси; (б) проверили, что принимающий сервис извлекает контекст, а не создаёт новый путь; (в) проверили инъекцию контекста в исходящие вызовы каждого сервиса; (г) проверили дерево пути и убедились в объединении спанов всех сервисов; (д) добавили запись о потере контекста, чтобы определять узел прерывания.
  4. Результат. Спаны всех сервисов объединяются в один путь, поэтому обработка видна целиком.

Вывод: промежуточный узел, не передающий заголовки контекста, разрывает путь между сервисами. Настройка передачи заголовков и проверка извлечения контекста на принимающей стороне восстанавливают непрерывность пути.

FAQ

Как контекст передаётся между сервисами? Через заголовки исходящего запроса. Принимающий сервис извлекает контекст и продолжает путь.

Что происходит при отсутствии извлечения контекста? Создаётся новый путь, поэтому связь с предыдущим участком теряется. Извлечение из входящих заголовков обеспечивает продолжение.

Как проверяется полнота пути? По дереву спанов: отсутствие спана на участке указывает на потерю контекста между сервисами.

Почему контекст теряется на прокси? Прокси может не передавать заголовки, поэтому принимающий сервис не получает контекст. Настройка передачи заголовков устраняет потерю.

Источники: W3C Trace Context, OpenTelemetry context propagation, OpenTelemetry Python — ссылки в шапке.