← Назад к вопросам
Кто формирует traceId для трассировки запроса
2.0 Middle🔥 201 комментариев
#REST API и микросервисы
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Кто формирует traceId для трассировки запроса
traceId — это уникальный идентификатор, связывающий все логи, метрики и spans одного запроса через распределённую систему. Это критично для debugging в микросервисной архитектуре.
Общая архитектура
Client Request
|
v
API Gateway (СОЗДАЁТ traceId, если его нет)
|
| traceId: "abc123" в header
v
Microservice 1 (читает traceId из header, передаёт дальше)
|
| вызов к Microservice 2
v
Microservice 2 (читает трас из header)
|
v
Database (логирует с traceId)
|
Logging Service (собирает все логи с одинаковым traceId)
Кто должен создавать traceId
1. API Gateway (entry point системы)
API Gateway отвечает за:
- Создание traceId если его нет в request
- Проверку формата
- Передачу во все микросервисы
// Spring Cloud Gateway + Spring Cloud Sleuth
@Component
public class TraceIdFilter extends AbstractGatewayFilterFactory<Config> {
private final TraceIdGenerator traceIdGenerator;
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String traceId = exchange.getRequest().getHeaders()
.getFirst("X-Trace-Id");
// Если нет — создаём
if (traceId == null) {
traceId = UUID.randomUUID().toString();
}
// Пробрасываем во все микросервисы
ServerWebExchange mutated = exchange.mutate()
.request(exchange.getRequest().mutate()
.header("X-Trace-Id", traceId)
.header("X-Span-Id", UUID.randomUUID().toString())
.build())
.build();
return chain.filter(mutated);
};
}
}
Почему Gateway:
- Один entry point — одно место для логики
- Видит все запросы
- Может добавить metadata (IP, User-Agent и т.д.)
2. Клиент (если есть)
Если клиент явно генерирует traceId — это тоже OK, но менее надёжно:
// Frontend
const traceId = crypto.randomUUID();
fetch('/api/orders', {
headers: {
'X-Trace-Id': traceId,
'X-Request-Id': traceId
}
});
Но лучше это делать на Gateway, потому что:
- Клиент может не отправить (JS отключен, мобильное приложение)
- Клиент может отправить невалидный ID
- Gateway точно включит все запросы
Распространение traceId в микросервисах
Spring Cloud Sleuth (автоматически)
Eсли используешь Spring Cloud Sleuth — всё работает на автопилоте:
// Зависимость
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
// Автоматически создаёт traceId и добавляет в MDC
@RestController
public class OrderController {
private static final Logger logger = LoggerFactory.getLogger(OrderController.class);
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest req) {
// Sleuth уже добавил traceId в MDC
logger.info("Creating order"); // логе будет [traceId=abc123]
return orderService.create(req);
}
}
// Логи видны как:
// 2024-03-22 10:15:30 [abc123] Creating order
// 2024-03-22 10:15:31 [abc123] Saving to database
// 2024-03-22 10:15:32 [abc123] Sending email
MDC (Mapped Diagnostic Context) — это механизм SLF4J для добавления context в каждый лог.
Ручное распространение (если нет Sleuth)
@RestController
public class OrderController {
private final OrderService orderService;
@PostMapping("/orders")
public Order createOrder(
@RequestBody OrderRequest req,
@RequestHeader("X-Trace-Id") String traceId) {
// Добавляем в MDC
MDC.put("traceId", traceId);
try {
return orderService.create(req, traceId);
} finally {
MDC.remove("traceId");
}
}
}
@Service
public class OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
public Order create(OrderRequest req, String traceId) {
logger.info("Creating order"); // будет [traceId=abc123]
// Передаём traceId при вызове другого сервиса
billingClient.createInvoice(req, traceId); // важно!
return repository.save(new Order());
}
}
// В HTTP клиенте
@Component
public class BillingClient {
private final RestTemplate restTemplate;
public void createInvoice(OrderRequest req, String traceId) {
HttpHeaders headers = new HttpHeaders();
headers.set("X-Trace-Id", traceId); // передаём дальше
HttpEntity<InvoiceRequest> entity = new HttpEntity<>(req, headers);
restTemplate.postForObject("/billing/invoices", entity, void.class);
}
}
Формат traceId
Стандартный (W3C Trace Context)
# W3C Trace Context (стандарт)
X-Trace-Id: 4bf92f3577b34da6a3ce929d0e0e4736
# Или с дополнительным context
X-Trace-Id: 4bf92f3577b34da6a3ce929d0e0e4736
X-Span-Id: 00f067aa0ba902b7
X-Parent-Span-Id: 00f067aa0ba902b8
X-Trace-Flags: 01
Микросервисы должны сохранять структуру
public class TraceContext {
private String traceId; // один для всей цепочки
private String spanId; // уникален для каждого шага
private String parentSpanId; // где он создан
// Пример трассировки запроса
// Gateway: traceId=abc123, spanId=span1
// -> OrderService: traceId=abc123, spanId=span2, parentSpan=span1
// -> BillingService: traceId=abc123, spanId=span3, parentSpan=span2
// -> Database: traceId=abc123, spanId=span4, parentSpan=span3
}
Практический пример: Spring + Sleuth + Zipkin
// pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
// application.yml
spring:
application:
name: order-service
zipkin:
base-url: http://zipkin:9411/ # адрес Zipkin сервера
sender:
type: web
sleuth:
sampler:
probability: 1.0 # трассировать все запросы (в продакшене < 1.0)
// Контроллер
@RestController
public class OrderController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest req) {
// Sleuth автоматически добавит в логи traceId
logger.info("Order requested: {}", req.getId());
return new Order();
}
}
// Результат в Zipkin UI:
// Видны все traces с их duration
// Можно щёлкнуть на trace и увидеть timeline всех операций
Где используется traceId
| Место | Использование |
|---|---|
| Логи | каждый лог содержит traceId |
| Метрики | прикреплены к trace (Prometheus) |
| APM (New Relic, DataDog) | группируют по trace |
| Алерты | "все запросы с traceId=abc имеют latency > 5s" |
| Debugging | "найти все действия пользователя по его ID" |
Правильный ответ на собеседовании
"traceId должен создавать API Gateway — это single entry point.
Процесс:
- Gateway проверяет заголовок
X-Trace-Id- Если его нет — создаёт (UUID)
- Пробрасывает во все микросервисы
- Каждый микросервис логирует с этим ID
- Логирует сервис (ELK, Splunk) может показать полный journey запроса
Инструменты:
- Spring Cloud Sleuth (автоматически)
- Spring Cloud Zipkin (визуализация)
- W3C Trace Context (стандарт)
Ключ: traceId = одинаковый для всей цепочки, spanId = уникален для каждого шага."