Розподілені трасування
Розподілені трасування
1) Навіщо і що це таке
Розподілене трасування - це спосіб зв'язати операції по всьому шляху запиту: фронт → API-шлюз → мікросервіси → БД/кеші → брокери → джоби/пайплайни.
Результат - трейс (trace) зі спанів (span), де кожен спан фіксує роботу компонента з атрибутами, подіями і статусом. Це прискорює RCA, допомагає тримати SLO і знижує MTTR.
- Видимість критичного шляху і «вузьких місць».
- Кореляція симптомів (метрики) з причинами (спани) і деталями (логи).
- Аналітика ретраїв, черг, DLQ, фан-аутів, «пилки» латентності.
2) Модель даних трасування
Trace - граф викликів з'trace _ id'.
Span - операція: `name`, `kind` (SERVER/CLIENT/PRODUCER/CONSUMER/INTERNAL), `start/end`, `status`, `attributes`, `events`, `links[]`.
Attributes - ключ-значення (route, db. system, messaging. system, cloud. region тощо).
Events - миттєві мітки всередині спану (наприклад, «retry», «cache _ miss»).
Span Links - зв'язки поза «батько-дитина» (батчі, ретраї, fan-in/out).
Resource - метадані процесу/сервісу ('service. name', версія, оточення).
3) Контекст і переносимість
3. 1 W3C Trace Context
Заголовки:- `traceparent`: 'version-traceid-spanid-flags'( прапори включають sampling).
- `tracestate`: вендор-специфічний стан (по мінімуму).
- Baggage - ключі для бізнес-контексту (обмежено, без PII/секретів).
3. 2 Прокидання контексту
HTTP: `traceparent`/`tracestate`; gRPC: метадані; WebSocket: при апгрейді і в повідомленнях;
Повідомлення: в headers (Kafka/NATS/RabbitMQ) - зберігаємо початковий контекст при PRODUCER і переносимо при CONSUMER.
Бази: не «несуть» контекст - логуємо атрибути в спан (query, rows, db. system), але не значення.
4) Семплювання: Як не розоритися
Head sampling (на вході): імовірнісне/за правилами (route, tenant, endpoint).
Tail sampling (на колекторі): зберігаємо «цікаві» трейси - помилки, довгі p95/p99, рідкісні шляхи.
Exemplars: метрики гістограми зберігають посилання на конкретні'trace _ id'.
Рекомендація: комбінувати - head 5-20% + tail-правила 100% для 5xx/timeout/p99.
5) Атрибути і таксономія (мінімум обов'язкового)
Загальні:- `service. name`, `service. version`, `deployment. environment`, `cloud. region`, `http. route`, `http. method`, `http. status_code`, `db. system`, `db. statement'( скорочено/без даних),'messaging. system`, `messaging. operation`, `peer. service`, `net. peer. name`, `tenant. id`, `request. id`.
Бізнес-лейбли: акуратно, без PII. Приклад: `order. segment`, `plan. tier`.
6) Асинхронні сценарії, черги і батчі
PRODUCER → CONSUMER: створюємо спан PRODUCER з контекстом; у повідомленні - headers (traceparent, baggage). CONSUMER стартує SERVER/CONSUMER-спан з link на PRODUCER (якщо немає суворої ієрархії).
Fan-out: один вхід - багато аутпутів → дочірні спани або links.
Batch: CONSUMER читає пачку N повідомлень → один спан з'events'по кожному messageId або'links'на N окремих контекстів.
DLQ: окремий спан'messaging. dlq. publish` с reason и count.
Ретраї: `event: retry` + `retry. count'атрибут; бажано новий CHILD-спан на спробу.
7) Інтеграція з логами та метриками
Логи пишемо JSON з'trace _ id '/' span _ id'→ зі спану кліком йдемо в логи.
Метрики RED/USE містять exemplars → з піків p99 йдемо в «погані» спани.
Траси генерують техсигнали (помилки залежностей) і бізнес-сигнали (конверсія) через події.
8) Продуктивність і вартість
Семплювання і троттлінг подій.
Скорочення кардинальності атрибутів (ніяких'user _ id '/' session _ id'як label!).
Стиснення/батчування експортером; межі таймаутів експорту.
Зберігання: гарячі 1-7 днів, далі - агрегати/тільки «проблемні» трейси.
Категорії витрат: колектори, індекси, сховище, egress.
9) Безпека і приватність
In Transit: TLS 1. 3/mTLS kollektor↔agenty; At Rest: шифрування, власні ключі (див. шифрування In Transit/At Rest).
PII і секрети: не пишемо в атрибути/події; токенізація/маскування на продьюсері.
Багатоарендність: `tenant. id'як ресурс-лейбл та ізоляція просторів, політики читання; аудіювання доступу до слідів (див. «Аудит і незмінні журнали»).
10) Схеми впровадження (референс)
10. 1 OpenTelemetry SDK (псевдокод)
python from opentelemetry import trace from opentelemetry. sdk. trace import TracerProvider from opentelemetry. sdk. resources import Resource from opentelemetry. sdk. trace. export import BatchSpanProcessor from opentelemetry. exporter. otlp. proto. grpc. trace_exporter import OTLPSpanExporter
provider = TracerProvider(resource=Resource. create({
"service. name":"checkout","service. version":"1. 12. 0","deployment. environment":"prod"
}))
provider. add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint="otel-collector:4317", insecure=True)))
trace. set_tracer_provider(provider)
tr = trace. get_tracer("checkout")
with tr. start_as_current_span("POST /pay", attributes={
"http. route":"/pay","http. method":"POST","tenant. id":"t-42"
}):
business logic, external API call and pass DB
10. 2 OTel Collector - tail sampling (фрагмент)
yaml processors:
tailsampling:
decision_wait: 2s policies:
- type: status_code status_codes: [ERROR]
- type: latency threshold_ms: 900
- type: probabilistic sampling_percentage: 10 exporters:
otlphttp: { endpoint: http://trace-backend:4318 }
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch, tailsampling]
exporters: [otlphttp]
10. 3 Kafka - перенесення контексту (концепція)
PRODUCER: додаємо headers'traceparent','baggage'.
CONSUMER: якщо повідомлення ініціює новий потік - новий SERVER/CONSUMER-спан c link на контекст з headers.
11) Data/ETL и ML
Для батч-пайплайнів: спан на батч/partition з'dataset. urn`, `run. id`, `rows. in/out`, `freshness. lag`.
Для ML: спани тренування/інференса, версія моделі, latency, feature store.
Зв'язка з Lineage: `run. id` и `dataset. urn'дозволяють від трейсу перейти до графу походження даних.
12) SLO платформи трасувань
Доступність ingestion: ≥ 99. 9%
Затримка до індексації: ≤ 60 з p95
Покриття head-sample: ≥ 5-10% ключових маршрутів
100% збереження трейсів зі статусом ERROR і з latency> порогу по каталогу «критичних шляхів»
Алерти платформи: зростання дропів, таймаути експорту, лаг індексатора, перегрів кардинальності.
13) Тестування та верифікація
Контракт трасування в CI: наявність спанів на ключових ендпоінтах, обов'язкові атрибути, коректний «traceparent» пролітає через шлюз/проксі.
Synthetic/rum-проби: збирають трейси із зовнішнього боку.
Chaos/інциденти: відключення залежностей, перевірка, що tail-семплер «підбирає» помилки.
Smoke в проді: після релізу - «чи є спани» і exemplar → трейс.
14) Чек-листи
Перед продом
- Скрізь прокинуть W3C Trace Context; для повідомлень - headers.
- Базове head-семплювання включено; tail-правила для 5xx/p99 налаштовані.
- Обов'язкові атрибути: route, method, status, service. version, tenant. id.
- Логи JSON з'trace _ id '/' span _ id', метрики з exemplars.
- Санітайзери PII; шифрування в дорозі/на спокої; політики доступу.
- Дашборди: «критичний шлях», «помилки залежностей», «ретраї/таймаути».
Експлуатація
- Щомісячний огляд кардинальності атрибутів; квоти.
- Тюнінг tail-семплінгу по SLO (менше шуму, все «гаряче» - у вибірці).
- Навчальні RCA з переходом метрика → exemplar → трейс → логи.
- Перевірка покриттів для черг, DLQ, ETL-джобів.
15) Runbook’и
RCA: зростання p99 на/pay
1. Відкрити RED-дашборд; з біна p99 перейти по exemplar в трейс.
2. Знайти «вузький» CLIENT-спан (наприклад,'gateway. call'), перевірити'retry. count', таймаути.
3. Порівняти версії сервісу/залежності, регіон/зону.
4. Увімкнути деградацію (кешуючий відповідь/ліміт RPS), повідомити власників залежності.
5. Після фіксу - RCA і тікети на оптимізацію.
DLQ сплеск
1. Фільтр трас по'messaging. dlq. publish`.
2. Перевірити причини (events), корелювати з релізом.
3. Запустити reprocess, тимчасово збільшити таймаут у CONSUMER, повідомити власників downstream.
16) Часті помилки
Немає прокидки контексту через шлюзи/брокери. Рішення: middleware/інтерсептори, єдині бібліотеки.
Всі трейси 100%. Дорого і безглуздо - використовуйте tail-семплінг.
Логи без'trace _ id'. Втрачається кореляція → MTTR ↑.
PII в атрибутах. Маскуйте/токенізуйте; зберігайте тільки технічний контекст.
«Німі» фонові джоби. Додайте спани на батч/partition і'run. id`.
Різнобій іменування. Введіть словник імен спанів і ключів атрибутів.
17) FAQ
В: Head або tail семплінг краще?
ПРО: Комбінація. Head дає базовий шар, tail гарантує збереження аномалій/помилок.
В: Як трасувати через Kafka без жорсткої ієрархії?
ПРО: Використовуйте span links між PRODUCER і CONSUMER; контекст - в headers.
В: Що робити з чутливими SQL?
ПРО: `db. statement'укорочений/нормалізований (без значень), або'db. operation'+ розміри/час.
В: Як зв'язати з бізнес-метриками?
ПРО: Додавайте атрибути домену без PII (plan/segment), використовуйте події «бізнес-етапів» всередині спану і переходьте з конверсійних метрик по exemplar.
- "Спостережуваність: логи, метрики, трасування"
- «Аудит і незмінні журнали»
- «Шифрування In Transit/At Rest»
- «Походження даних (Lineage)»
- «Privacy by Design (GDPR)»
- «Менеджмент секретів»