Уяви, що ти замовив піцу через додаток. Ти натискаєш кнопку "Замовити", і твій запит відправляється в мікросервіс, який відповідає за оформлення замовлення. Цей мікросервіс запитує дані іншого сервісу — того, що керує списком піц. Потім підключається ще один сервіс, який рахує доставку, і потім ще один — для оплати. Отже, на перший погляд простий запит проходить через багато сервісів, кожен із яких може залишити свій "слід".
Розподілене трасування (Distributed Tracing) — це процес відстеження "подорожі" твого запиту через усі ці сервіси. Воно допомагає зрозуміти, через які компоненти проходить запит, скільки часу він витрачає на кожному етапі і де саме він може гальмувати.
Основні задачі розподіленого трасування:
- Показати весь шлях виконання запиту.
- Виявити вузькі місця і повільні операції.
- Діагностувати помилки та збої.
- Покращити продуктивність і оптимізувати архітектуру.
Якщо говорити про розподілене трасування у світі мікросервісів, воно стає основним інструментом, щоб не загубитися в складній павутині взаємодій між сервісами.
Фундаментальні поняття
У розподіленому трасуванні є два ключові поняття:
- Trace (траса) — це повний шлях запиту від початку до кінця. Наприклад, запит на оформлення замовлення може починатися в веб-застосунку і закінчуватися в сервісі доставки, а Trace об'єднує всі ці етапи.
- Span (спан) — це окремий крок всередині Trace. Кожен виклик мікросервісу, звернення до бази даних або виклик об'єкта через HTTP вважається Span'ом.
На практиці це виглядає як дерево: кожен Trace містить багато Span'ів, і вони діляться на дочірні та батьківські дії.
Навіщо потрібне розподілене трасування?
- Розбиратися в складних взаємодіях: коли запит "застрягає", трасування допоможе зрозуміти, де саме щось пішло не так. Наприклад, сервіс доставки може затримувати відповідь через повільне з'єднання з базою даних.
- Зменшити час простою: трасування допомагає швидко зрозуміти, які компоненти ламаються, і де саме знаходяться вузькі місця.
- Оптимізувати продуктивність: виміри часу виконання операцій дозволяють знаходити ділянки коду або взаємодій, які треба покращити.
- Забезпечити прозорість: якщо ти працюєш у команді, трасування робить систему більш зрозумілою для всіх. Все, що відбувається між сервісами, документується.
Основні компоненти розподіленого трасування
Span і Trace: тандем, який усе пояснює.
Трошки про Span:
- Span — це одинична дія, наприклад, виклик REST API або операція запису в базу даних.
- У кожного Span є унікальний ідентифікатор, який пов'язує його з трасою і іншими спанами.
І трохи про Trace:
- Trace об'єднує багато Span'ів в одне ціле.
- У Trace теж є свій унікальний ідентифікатор, щоб показати, що всі Spans належать одному запиту.
Приклад:
Trace ID: 987654321
├── Span ID: 1 (Customer Service - обробка замовлення)
├── Span ID: 2 (Pizza Service - перевірка наявності піци)
├── Span ID: 3 (Delivery Service - розрахунок доставки)
└── Span ID: 4 (Payment Service - опрацювання оплати)
Спостереження: кожен крок має довжину Span.
Інструменти для реалізації розподіленого трасування
Є кілька інструментів, які спрощують реалізацію трасування в мікросервісах. Розглянемо два найпопулярніші:
1. Zipkin
Zipkin — це інструмент для збору й візуалізації даних трасування. Він дозволяє зберігати й аналізувати дані про час виконання кожного запиту.
- Плюси: Простота налаштування, підтримка багатьох мов програмування.
- Мінус: Обмежені можливості для метрик і моніторингу (тільки трасування).
2. OpenTelemetry
OpenTelemetry — це більш сучасний підхід, який об'єднує трасування, метрики і логи в одному інструменті. Його можна вважати універсальним рішенням для Observability.
- Плюси: Підтримка кількох стандартів, гнучкість.
- Мінус: Складніше налаштувати порівняно з Zipkin.
Офіційна документація OpenTelemetry
Як працює розподілене трасування?
Процес роботи можна описати так:
- Генерація Trace ID: коли запит потрапляє в систему, створюється унікальний ідентифікатор для Trace.
- Генерація Span ID: кожна дія в рамках цього Trace отримує свій унікальний Span ID.
- Передача контексту: Trace ID і Span ID передаються між сервісами за допомогою заголовків HTTP.
- Збір даних: кожен сервіс записує дані про час виконання, помилки та інші події.
- Аналіз: всі дані надсилаються в інструмент (наприклад, Zipkin), де ти можеш візуалізувати весь процес.
Приклад взаємодії мікросервісів з трасуванням
Уяви таку схему взаємодій:
Client -> Order Service -> Inventory Service -> Payment Service
Спочатку Клієнт надсилає запит до Order Service (мікросервіс оформлення замовлення). Той, у свою чергу, викликає:
- Inventory Service для перевірки залишків на складі.
- Payment Service для підтвердження платежу.
Розподілене трасування створить дерево запитів, яке покаже:
- Скільки часу зайняв Order Service.
- Де саме запит затримався (наприклад, на етапі перевірки складу).
- Якщо виникла помилка, в якому сервісі вона сталася.
Як це допомагає в реальному житті?
Розподілене трасування стає особливо корисним, коли система розростається до десятків і сотень мікросервісів. У такій системі:
- Помилки можуть відбуватися де завгодно.
- Ручний пошук проблеми стає неможливим.
- Тестування всіх взаємодій ускладнюється.
Трасування бере на себе задачу "повішати ярлики" на кожному запиті і дає розробнику все необхідне для швидкого аналізу.
На наступній лекції поговоримо про те, як інтегрувати Spring Boot з Zipkin і Sleuth. Для цього візьмемо кілька мікросервісів, підключимо бібліотеки трасування і навчимося "бачити" запити в інтерфейсі Zipkin. Готуйся до практики — буде цікаво!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ