Tracing
Tracing distribué avec Sleuth et Zipkin
10-15 min
Tracing Distribué avec Sleuth et Zipkin
Le tracing distribué est essentiel pour comprendre et déboguer les interactions entre les microservices. Spring Cloud Sleuth et Zipkin permettent de suivre les requêtes à travers l’ensemble de l’architecture.
1. Configuration de Base
1.1 Ajout des Dépendances
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
1.2 Configuration de Sleuth
# application.yml
spring:
application:
name: product-service
sleuth:
otel:
config:
trace-id-ratio-based: 1.0
propagation:
type: w3c
sampler:
probability: 1.0
zipkin:
base-url: http://localhost:9411
sender:
type: web
2. Configuration de Zipkin
2.1 Installation de Zipkin
docker run -d -p 9411:9411 openzipkin/zipkin
2.2 Configuration des Services
# application.yml
spring:
zipkin:
base-url: http://localhost:9411
sender:
type: web
service:
name: ${spring.application.name}
3. Implémentation du Tracing
3.1 Configuration du Tracer
@Configuration
public class TracingConfig {
@Bean
public Tracer tracer() {
return new Tracer.Builder()
.withSampler(Sampler.ALWAYS_SAMPLE)
.build();
}
}
3.2 Utilisation dans les Services
@Service
@Slf4j
public class ProductService {
private final Tracer tracer;
private final ProductRepository productRepository;
public ProductService(Tracer tracer, ProductRepository productRepository) {
this.tracer = tracer;
this.productRepository = productRepository;
}
public Product getProduct(Long id) {
Span span = tracer.nextSpan().name("getProduct");
try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
log.info("Fetching product with id: {}", id);
return productRepository.findById(id)
.orElseThrow(() -> new ProductNotFoundException(id));
} finally {
span.finish();
}
}
}
4. Intégration avec les Clients HTTP
4.1 Configuration du RestTemplate
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(Tracer tracer) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Collections.singletonList(
new TracingRestTemplateInterceptor(tracer)
));
return restTemplate;
}
}
4.2 Intercepteur de Tracing
public class TracingRestTemplateInterceptor implements ClientHttpRequestInterceptor {
private final Tracer tracer;
public TracingRestTemplateInterceptor(Tracer tracer) {
this.tracer = tracer;
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestInterceptor.ClientHttpRequestExecution execution) throws IOException {
Span span = tracer.nextSpan().name("http-request");
try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
request.getHeaders().add("X-Trace-ID", span.context().traceId());
return execution.execute(request, body);
} finally {
span.finish();
}
}
}
5. Monitoring et Visualisation
5.1 Configuration des Métriques
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
5.2 Métriques Personnalisées
@Component
public class TracingMetrics {
private final MeterRegistry registry;
private final Tracer tracer;
public TracingMetrics(MeterRegistry registry, Tracer tracer) {
this.registry = registry;
this.tracer = tracer;
registerMetrics();
}
private void registerMetrics() {
Gauge.builder("tracing.active.spans", tracer, this::getActiveSpans)
.description("Number of active spans")
.register(registry);
Counter.builder("tracing.spans")
.description("Number of spans")
.tag("type", "http")
.register(registry);
}
private double getActiveSpans(Tracer tracer) {
return tracer.currentSpan() != null ? 1 : 0;
}
}
6. Tests
6.1 Test d’Intégration
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TracingIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void whenGetProduct_thenTraceIsGenerated() {
// Act
ResponseEntity<Product> response = restTemplate.getForEntity(
"/api/products/1", Product.class);
// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
assertTrue(response.getHeaders().containsKey("X-Trace-ID"));
}
}
6.2 Test du Tracer
@SpringBootTest
class TracerTest {
@Autowired
private Tracer tracer;
@Test
void whenCreateSpan_thenSpanIsCreated() {
// Act
Span span = tracer.nextSpan().name("test-span");
try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
assertNotNull(span);
assertNotNull(span.context());
assertNotNull(span.context().traceId());
} finally {
span.finish();
}
}
}
Conclusion
Le tracing distribué avec Sleuth et Zipkin offre plusieurs avantages :
- Visualisation complète des interactions entre services
- Identification rapide des goulots d’étranglement
- Débogage facilité des problèmes distribués
- Métriques détaillées sur les performances
- Intégration native avec Spring Cloud
Dans le prochain tutoriel, nous verrons comment sécuriser nos microservices avec Spring Security et OAuth2.
Commentaires
Les commentaires sont alimentés par GitHub Discussions
Connectez-vous avec GitHub pour participer à la discussion