Trace context через live-data path: HTTP, очередь и fan-out
Trace context должен пережить HTTP, очередь, worker и fan-out, но не подменять предметные event/version identifiers, без которых невозможно объяснить состояние данных.
carrier → extract → context → process → inject → carrierТранспорт меняется; инварианты идентичности, версии и корреляции должны оставаться проверяемыми.

Live-data path редко остаётся одним HTTP-запросом. Событие проходит collector, queue, worker, normalization, pricing, cache и API fan-out. Если trace context теряется на первой асинхронной границе, dashboard показывает десяток отдельных операций вместо одной причинной цепочки.
Определить границы, где контекст обязан пережить переход
Сначала рисуют реальный path и отмечают смену transport: HTTP → broker, broker → worker, worker → downstream API, batch/fan-out. Для каждой границы нужен carrier и понятная политика propagation. OpenTelemetry описывает context как механизм передачи execution-scoped значений; практический смысл здесь — не дать trace identifier исчезнуть при переходе между компонентами.
Источник: OpenTelemetry Context specification.
Асинхронность меняет модель причинности
Producer span завершился до того, как consumer начал работу; один message может породить несколько downstream операций. Не стоит притворяться, что это обычный синхронный вызов. Инструментация должна отражать publish/consume relationship и сохранять связь, достаточную для расследования задержки и конкретной версии данных.
Trace ID не заменяет предметный идентификатор
Для sports feed нужны event/entity/version identifiers, для pricing — market/version, для incident recovery — replay range или checkpoint. Trace помогает связать технические операции, но не объясняет, какое бизнес-состояние они переносили. Лучший diagnostic record сочетает оба типа идентификаторов.
Baggage — не место для чувствительных данных
Удобство propagation создаёт соблазн передавать в baggage email, token, account identifier или произвольный payload. Это опасно: context может пройти через множество сервисов и экспортёров. В него стоит класть только минимальные безопасные атрибуты, действительно нужные downstream. Чувствительные данные и секреты туда не относятся.
Sampling не должен уничтожать инцидентный след
Высокий трафик заставляет семплировать traces, но редкий failure может исчезнуть именно в момент расследования. Политика sampling должна учитывать error/security/incident signals и возможность повысить детализацию на ограниченном scope. При этом audit trail и предметные event logs остаются отдельным источником фактов; tracing не обязан хранить всё.
Как проверить propagation без красивого демо
Возьмите один тестовый event, проведите его через очередь и fan-out, затем по конечному API/result попытайтесь найти исходный ingest span. Повторите сценарий после retry и reconnect. Если приходится вручную сопоставлять timestamps из пяти систем, context propagation работает только частично.
Что смотреть при росте latency
Полезно сравнить event time, queue wait, processing duration, publish time и client-visible version. Тогда trace показывает не просто «worker занял 800 мс», а где именно вырос возраст состояния. Для live-data это важнее абсолютной длительности одного span.
Не каждый атрибут обязан становиться span attribute
Высокая cardinality быстро делает tracing дорогим и неудобным. Competition, provider или operation class могут быть полезны для фильтрации, а уникальные payload fragments и чувствительные идентификаторы — нет. Детали конкретной сущности лучше связывать через безопасный предметный ID и искать в специализированном журнале событий. Так trace остаётся инструментом навигации по пути, а не копией всех данных системы.
Fan-out иногда требует links, а не искусственного parent
Когда одно событие запускает несколько независимых обработок или batch собирает сообщения из разных источников, строгая parent-child цепочка может искажать причинность. Инструментация должна отражать реальную модель выполнения, используя поддерживаемые механизмом tracing связи там, где один родитель не подходит. Для дежурного важнее сохранить путь от конкретной published version к набору операций, чем добиться визуально идеально вложенного waterfall.
При повторной обработке одного event новый trace не обязан копировать старый trace ID. Важнее сохранить ссылку на исходный business/event identifier и отметить, что текущая обработка является replay. Это позволяет различать оригинальный live-path и восстановительную процедуру.
Для batch-процессов полезно дополнительно сохранять run ID и диапазон входных событий. Это помогает связать traces с конкретным backfill/replay и не путать восстановительную обработку с live-трафиком.
Business identifier нужен даже при идеальном tracing
Trace хорошо показывает техническую причинность, но replay или повторная обработка могут получить новый trace id. Поэтому event/version id остаётся отдельной осью корреляции. Это особенно важно для out-of-order событий и corrections: по одному trace нельзя понять, что две обработки относятся к одной предметной версии, если связь не сохранена в безопасном идентификаторе. В результате tracing помогает найти путь, а business id — доказать, какое состояние по нему проходило.
Отдельная проблема — потеря контекста при batch и fan-out. Один входной event может породить десятки операций, а несколько сообщений — объединиться в один расчёт. В таких местах строгая parent-child модель не всегда отражает реальность. Важнее сохранить links и предметные IDs так, чтобы инженер мог перейти от конкретной client-visible версии к набору upstream операций, не создавая искусственную причинность ради красивого waterfall.