Распределённая трассировка

Настройте распределённую трассировку для отслеживания запросов между микросервисами.

Обзор

Трейсы показывают поток запроса через вашу систему:

  • Спаны: отдельные операции (запрос к БД, HTTP-вызов)
  • Связи «родитель-потомок»: иерархия вызовов
  • Тайминг: длительность каждой операции
  • Атрибуты: метаданные (user_id, endpoint, status)

Базовая настройка

Node.js

const { trace } = require('@opentelemetry/api');
const tracer = trace.getTracer('my-service');

app.get('/api/users/:id', async (req, res) => {
  const span = tracer.startSpan('get_user');

  try {
    const user = await db.query('SELECT * FROM users WHERE id = ?', [req.params.id]);
    span.setAttribute('user.id', user.id);
    span.setAttribute('user.plan', user.plan);
    res.json(user);
  } catch (error) {
    span.recordException(error);
    span.setStatus({ code: SpanStatusCode.ERROR });
    throw error;
  } finally {
    span.end();
  }
});

Python

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

@app.route('/api/users/<user_id>')
def get_user(user_id):
    with tracer.start_as_current_span("get_user") as span:
        span.set_attribute("user.id", user_id)
        user = db.query(f"SELECT * FROM users WHERE id = {user_id}")
        span.set_attribute("user.plan", user['plan'])
        return jsonify(user)

Go

import "go.opentelemetry.io/otel"

func getUser(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    tracer := otel.Tracer("my-service")

    ctx, span := tracer.Start(ctx, "get_user")
    defer span.End()

    userID := r.URL.Query().Get("id")
    span.SetAttributes(attribute.String("user.id", userID))

    user, err := db.QueryContext(ctx, "SELECT * FROM users WHERE id = ?", userID)
    if err != nil {
        span.RecordError(err)
        span.SetStatus(codes.Error, err.Error())
        return
    }

    json.NewEncoder(w).Encode(user)
}

Атрибуты спана

Добавляйте контекст к спанам:

span.setAttribute('http.method', 'POST');
span.setAttribute('http.url', '/api/orders');
span.setAttribute('http.status_code', 200);
span.setAttribute('user.id', '12345');
span.setAttribute('order.id', 'ORD-789');
span.setAttribute('order.total', 49.99);

Вложенные спаны

Отслеживание под-операций:

const parentSpan = tracer.startSpan('process_order');

// Child span 1
const validateSpan = tracer.startSpan('validate_order', { parent: parentSpan });
validateOrder();
validateSpan.end();

// Child span 2
const chargeSpan = tracer.startSpan('charge_payment', { parent: parentSpan });
await chargePayment();
chargeSpan.end();

parentSpan.end();

Распространение контекста

Трассировка между сервисами:

Сервис A (вызывающий)

const { propagation, context } = require('@opentelemetry/api');

const headers = {};
propagation.inject(context.active(), headers);

fetch('http://service-b/api/endpoint', { headers });

Сервис B (принимающий)

const extractedContext = propagation.extract(context.active(), req.headers);

context.with(extractedContext, () => {
  const span = tracer.startSpan('handle_request');
  // Span is automatically child of Service A's span
});

Сэмплирование

Управление тем, какие трейсы собирать:

const { TraceIdRatioBasedSampler } = require('@opentelemetry/sdk-trace-base');

const provider = new TracerProvider({
  sampler: new TraceIdRatioBasedSampler(0.1)  // Sample 10%
});

Просмотр трейсов

Dashboard → Observability → Apps → [Your App] → Traces

Возможности:

  • Визуализация таймлайна трейса
  • Граф зависимостей сервисов
  • Подсветка трейсов с ошибками
  • Фильтрация медленных трейсов
  • Поиск по атрибутам спанов

Лучшие практики

СТОИТ:

  • Использовать семантические соглашения (http., db. и т. д.)
  • Добавлять бизнес-контекст (user_id, order_id)
  • Сэмплировать высоконагруженные эндпоинты
  • Распространять контекст между сервисами

НЕ СТОИТ:

  • Включать чувствительные данные в атрибуты
  • Создавать слишком много спанов (>100 на трейс)
  • Забывать завершать спаны
  • Блокировать выполнение на экспорте спанов

Дальнейшие шаги

  • Логи — корреляция логов с трейсами
  • Метрики — отслеживание метрик трейсов
  • SDK — руководства по конкретным языкам