Этот вопрос проверяет понимание наблюдаемости распределённых систем: умение использовать логи, трассировку и корреляционные идентификаторы, чтобы найти, где именно в цепочке микросервисов произошёл сбой.
Главный инструмент для определения этапа сбоя — сквозная корреляция запросов через все сервисы. Для этого каждому запросу назначают trace_id/request_id и передают его в заголовках между сервисами, записывая в логах и метриках.
Далее, используя систему логирования или трассировки (например, Jaeger, Zipkin, OpenTelemetry), можно просмотреть цепочку вызовов и увидеть, на каком сервисе появилась ошибка или аномально выросла задержка.
Дополнительно помогают метрики (ошибки, латентность, количество запросов) и алерты: по ним видно, какой сервис “краснеет” в момент проблемы.
В итоге точка сбоя находится по комбинации: корреляционный ID + логи + трассировка + метрики.
Определить, на каком этапе цепочки сервисов произошёл сбой, можно только при хорошо организованной наблюдаемости. Важны единые идентификаторы запросов, структурированное логирование и распределённая трассировка.
Определение:Корреляционный идентификатор — это уникальный ID, который присваивается запросу и передаётся через все сервисы, участвующие в его обработке.
На входе в первый сервис создаётся request_id (например, UUID).
request_id сохраняется в контексте и логируется во всех сообщениях, связанных с этим запросом.
При вызове следующего сервиса ID передаётся в заголовке, например X-Request-ID или traceparent (OpenTelemetry).
В логах всех сервисов по этому ID можно собрать полную историю запроса.
Пример (упрощённо, Python + FastAPI):
import uuid
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def add_request_id(request: Request, call_next):
request_id = request.headers.get("X-Request-ID", str(uuid.uuid4()))
# здесь можно положить request_id в контекст логгера
response = await call_next(request)
response.headers["X-Request-ID"] = request_id
return response
Далее в каждом лог-сообщении нужно включать request_id.
Определение:Структурированное логирование — это логирование в формате, который легко парсить машиной (например, JSON с фиксированными полями).
Что важно:
всегда логировать:
timestamp
service_name
request_id / trace_id
endpoint / operation
status (успех/ошибка)
error / exception при проблеме
использовать централизованный сбор логов (ELK, Loki и т.п.)
Тогда, чтобы найти сбой:
Берём request_id проблемного запроса.
Фильтруем логи по этому ID.
Смотрим по времени: какой сервис последний отдал 200, а какой первый вернул ошибку или завис.
Определение:Распределённая трассировка — это способ визуально и технически отслеживать путь запроса через множество сервисов, разбивая его на спаны (spans).
Инструменты: Jaeger, Zipkin, OpenTelemetry.
Как это помогает:
видим дерево вызовов: Gateway → Auth → OrderService → PaymentService
по каждому спану:
время начала/конца
статус (OK/ERROR)
метаданные (URL, код ответа)
на графике сразу видно:
где ошибка (спан со статусом ERROR)
где “бутылочное горлышко” по времени
Метрики дополняют картину:
error_rate по сервисам и их методам
latency (p95, p99)
throughput (RPS)
Если внезапно растёт error_rate у конкретного сервиса, именно он — кандидат на точку сбоя. Дальше уже смотрим трассировку и логи по request_id.
Пользователь сообщает о проблеме или алерт срабатывает на рост ошибок.
Находим конкретный запрос (по времени, пользователю и т.д.) и его request_id.
Открываем:
трассировку по этому request_id
логи по этому ID
Определяем:
какой сервис первый вернул ошибку
либо где сильно выросла задержка без явной ошибки
Переходим к детальной диагностике уже конкретного сервиса.
Чтобы понять, где в цепочке сервисов произошёл сбой, нужны:
единый request_id/trace_id во всех сервисах,
структурированные логи,
распределённая трассировка,
метрики и алерты.
Без этого поиск точки отказа превращается в ручной перебор и угадайку.