中文翻译暂不可用,显示俄语原文。

Настроить distributed tracing

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить distributed tracing

1. Цель задачи

Настроить сквозную распределённую трассировку (distributed tracing) между агентами многокомпонентной системы. Каждое меж-агентское сообщение должно содержать уникальный trace_id, который позволяет восстановить полную цепочку вызовов от инициатора до всех вложенных агентов. Это даст возможность анализировать задержки, ошибки и зависимости в архитектуре, где агенты общаются через асинхронные очереди (RabbitMQ) или синхронные вызовы (gRPC/HTTP).

Ключевой результат Работающий дашборд в Jaeger/Zipkin, отображающий спаны для каждого шага общения агентов, с trace_id, передаваемым через заголовки сообщений.

2. Исходные данные

Что нужноОткуда взять
Многокомпонентная система агентов (2+ агента)Собранный пет-проект (например, на LangGraph, CrewAI) или самописные микросервисы
Очередь сообщений или RPC-канал между агентамиRabbitMQ, Kafka, gRPC, HTTP (на выбор; предпочтительно RabbitMQ)
Docker / Docker ComposeЛокальная установка
Python 3.10+Установлен в окружении
OpenTelemetry Python SDKpip install opentelemetry-api opentelemetry-sdk
Jaeger (или Zipkin) для визуализацииdocker run -p 16686:16686 jaegertracing/all-in-one:latest

Если нет реального инструмента — симулируем:

  1. Напишите двух простых Python-сервисов (агент A и агент B), общающихся через RabbitMQ (или gRPC).
  2. Используйте aio_pika для RabbitMQ или grpc для синхронных вызовов.
  3. Разверните Jaeger all-in-one в Docker Compose.
  4. Инструментируйте оба сервиса с помощью OpenTelemetry.

3. Технологический стек

КомпонентИнструментыНазначение
ЯзыкPython 3.10+Реализация агентов
АгентыLangGraph / CrewAI / самописные asyncio-сервисыМногокомпонентная система
Транспорт между агентамиRabbitMQ / gRPC / HTTP (REST)Передача сообщений
ТрассировкаOpenTelemetry SDK, OpenTelemetry Python APIsГенерация спанов и контекста
Бэкенд трейсовJaeger (all-in-one) / ZipkinХранение и визуализация
КонтейнеризацияDocker + Docker ComposeОкружение для запуска
Python-клиентыopentelemetry-exporter-otlp, opentelemetry-instrumentationИнструментирование HTTP/gRPC/AMQP

4. Этапы выполнения

Этап 1: Подготовка окружения и запуск Jaeger (30 минут)

Действия

  1. Создать директорию проекта distributed-tracing-lab.
  2. В корне создать docker-compose.yml с сервисом Jaeger:
    version: '3'
    services:
      jaeger:
        image: jaegertracing/all-in-one:latest
        ports:
          - "16686:16686"   # UI
          - "4317:4317"     # OTLP gRPC
          - "4318:4318"     # OTLP HTTP
    
  3. Запустить docker compose up -d jaeger.
  4. Проверить UI: открыть http://localhost:16686.

Ожидаемый результат этапа Запущенный Jaeger, пустой дашборд.

Этап 2: Создание тестовой системы агентов (1 час)

Действия

  1. Написать agent_a.py и agent_b.py с базовым обменом через RabbitMQ (или gRPC). Пример для RabbitMQ:
    • Агент A получает HTTP-запрос, создаёт задачу, шлёт сообщение в очередь tasks.
    • Агент B слушает tasks, выполняет работу, отправляет результат в очередь results.
    • Агент A потребляет results и возвращает финальный ответ.
  2. Установить зависимости:
    pip install aio-pika opentelemetry-distro
    opentelemetry-bootstrap -a install
    
  3. Убедиться, что система работает без трассировки (простое логирование).

Ожидаемый результат этапа Рабочая коммуникация между двумя агентами, сообщения передаются через брокер (или gRPC).

Этап 3: Инструментирование OpenTelemetry (1.5 часа)

Действия

  1. В каждом агенте инициализировать TracerProvider и экспортёр OTLP:
    from opentelemetry import trace
    from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    
    provider = TracerProvider()
    exporter = OTLPSpanExporter(endpoint="localhost:4317", insecure=True)
    provider.add_span_processor(BatchSpanProcessor(exporter))
    trace.set_tracer_provider(provider)
    tracer = trace.get_tracer(__name__)
    
  2. Создать корневой span при входящем запросе к Agent A.
  3. При отправке сообщения в RabbitMQ (или gRPC) передать контекст трассировки через заголовки:
  4. В Agent B при получении сообщения извлечь контекст с помощью propagators:
    from opentelemetry import propagate
    ctx = propagate.extract(carrier=headers)  # headers — словарь из сообщения
    with tracer.start_as_current_span("agent_b_process", context=ctx):
        # обработка
    
  5. Добавить вложенные спаны для каждой значимой операции (parse, call external API, write to DB).

Ожидаемый результат этапа При запуске цепочки запросов в Jaeger появляются трейсы, состоящие из нескольких спанов (для Agent A и Agent B).

Этап 4: Проверка передачи trace_id и визуализация (30 минут)

Действия

  1. Отправить несколько тестовых запросов через Agent A (например, через curl или Python requests).
  2. Открыть Jaeger UI, найти трейс по service name agent_a.
  3. Убедиться, что:
    • В трейсе есть спаны обеих служб.
    • trace_id одинаковый для всех спанов одной цепочки.
    • Видны временные метки и длительности каждого шага.
  4. Проверить, что traceparent передаётся в заголовках сообщений (можно включить отладочный вывод).

Ожидаемый результат этапа В Jaeger отображаются полные трейсы меж-агентских вызовов.

Этап 5: Документирование и автоматизация (30 минут)

Действия

  1. Написать README.md с инструкцией по запуску: docker compose up, запуск агентов, пример запроса.
  2. Создать Makefile или bash-скрипт для однокомандного запуска всей системы.
  3. Добавить в код комментарии о том, как контекст прокидывается через брокер.

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

5. Критерии приемки (Definition of Done)

  • Jaeger UI запущен и доступен по адресу http://localhost:16686.
  • Два агента обмениваются сообщениями через выбранный транспорт (RabbitMQ/gRPC/HTTP).
  • При старте каждого агента инициализируется OpenTelemetry TracerProvider с экспортом в Jaeger.
  • При отправке сообщения от Agent A к Agent B в заголовки добавляется traceparent.
  • При получении сообщения Agent B извлекает контекст и создаёт дочерние спаны.
  • В Jaeger отображается полный трейс для каждого запроса, содержащий спаны обеих служб.
  • trace_id един для всех спанов одной цепочки (проверено по UI).
  • Код задокументирован (README, комментарии).
  • Система воспроизводится одной командой docker compose up + запуск агентов.
  • Тестовый запрос (например, POST на Agent A) возвращает ответ, а трейс отображается в Jaeger за < 1 секунды.

6. Ожидаемый результат

  • Артефакт Папка distributed-tracing-lab с файлами: docker-compose.yml, agent_a.py, agent_b.py, requirements.txt, Makefile, README.md.
  • Содержание Рабочая система distributed tracing для двух агентов с передачей контекста через сообщения.
  • Опционально Графики в Jaeger (скриншот трейса приложен к задаче), скрипт для нагрузки (test.sh).

7. Возможные сложности и их решение

СложностьРешение
OpenTelemetry не видит библиотеку RabbitMQ (aio-pika)Использовать opentelemetry-instrumentation с aio-pika или вручную создать спаны при отправке/получении
Контекст не передаётся через RabbitMQУбедиться, что используется W3C traceparent в заголовках сообщения и propagate.extract вызывается на стороне потребителя
Jaeger не показывает спаныПроверить, что экспортёр OTLP отправляется на правильный порт (4317), и что Jaeger слушает gRPC
Разные trace_id для одного запросаПроверить, что при извлечении контекста не создаётся новый корневой span вместо дочернего
Зависимости конфликтуют (версии OpenTelemetry)Использовать opentelemetry-distro и opentelemetry-bootstrap, зафиксировать версии в requirements.txt
Задержки при старте из-за RabbitMQИспользовать docker compose с зависимостью depends_on на rabbitmq

8. Бюджет времени (оценка)

ЭтапВремя
Подготовка окружения и запуск Jaeger30 мин
Создание тестовой системы агентов1 ч
Инструментирование OpenTelemetry1 ч 30 мин
Проверка передачи trace_id и визуализация30 мин
Документирование и автоматизация30 мин
Итого4 ч

Примечание: Для первого исполнителя с нулевым опытом OpenTelemetry время может увеличиться до 6-8 часов. Рекомендуется предварительно пройти quickstart OpenTelemetry для Python.

9. Связанные вопросы из базы знаний

ВопросТема
12Что такое distributed tracing и зачем он нужен в multi-agent системах?
34Как работает OpenTelemetry propagators?
89Формат W3C trace-context: traceparent и tracestate
145Инструментирование RabbitMQ с OpenTelemetry в Python
203Сравнение Jaeger и Zipkin
267Настройка batch span processor
310Как дебажить проблемы с экспортом трейсов?
422gRPC metadata propagation для trace context
578Интеграция OpenTelemetry с LangGraph
601Мониторинг задержек между агентами через дашборды

10. Чек-лист самопроверки

  • Я запустил Jaeger через Docker Compose и убедился, что UI доступен.
  • Мои агенты общаются через брокер (RabbitMQ) или RPC, и я вижу логи сообщений.
  • Я добавил импорты и инициализацию OpenTelemetry в каждом агенте.
  • При отправке сообщения я вставил заголовок traceparent (или traceparent + tracestate).
  • При получении сообщения я вызвал extract и использовал полученный контекст при создании нового span.
  • Я отправил тестовый запрос и увидел в Jaeger трейс, содержащий спаны обеих служб с одинаковым trace_id.
  • Я написал README и Makefile для воспроизведения на чистом окружении.