Communication entre microservices
Les différentes stratégies de communication
Communication entre microservices
Dans ce chapitre, nous explorerons les différentes stratégies de communication entre microservices. Nous verrons comment implémenter et utiliser chaque approche avec Spring Cloud.
1. Communication REST avec OpenFeign
Configuration
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Implémentation
@FeignClient(name = "order-service", url = "${order.service.url}")
public interface OrderClient {
@GetMapping("/api/orders/{id}")
OrderDTO getOrder(@PathVariable("id") Long id);
@PostMapping("/api/orders")
OrderDTO createOrder(@RequestBody CreateOrderRequest request);
}
Utilisation
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderClient orderClient;
public OrderDTO getOrderDetails(Long orderId) {
return orderClient.getOrder(orderId);
}
}
2. Messaging avec RabbitMQ
Configuration
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
Configuration RabbitMQ
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
Implémentation du Producteur
@Component
@RequiredArgsConstructor
public class OrderEventProducer {
private final RabbitTemplate rabbitTemplate;
public void sendOrderCreatedEvent(OrderCreatedEvent event) {
rabbitTemplate.convertAndSend(
"order-exchange",
"order.created",
event
);
}
}
Implémentation du Consommateur
@Component
@RequiredArgsConstructor
public class OrderEventConsumer {
private final ProductService productService;
@RabbitListener(queues = "order-queue")
public void handleOrderCreatedEvent(OrderCreatedEvent event) {
// Traitement de l'événement
productService.updateStock(event.getProductId(), event.getQuantity());
}
}
3. Communication gRPC
Configuration
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.42.1</version>
</dependency>
Définition du Service
syntax = "proto3";
package com.example.product;
service ProductService {
rpc GetProduct (ProductRequest) returns (ProductResponse) {}
rpc UpdateStock (UpdateStockRequest) returns (UpdateStockResponse) {}
}
message ProductRequest {
int64 id = 1;
}
message ProductResponse {
int64 id = 1;
string name = 2;
int32 stock = 3;
}
message UpdateStockRequest {
int64 id = 1;
int32 quantity = 2;
}
message UpdateStockResponse {
bool success = 1;
int32 newStock = 2;
}
Implémentation du Serveur
@GrpcService
public class ProductGrpcService extends ProductServiceGrpc.ProductServiceImplBase {
private final ProductService productService;
@Override
public void getProduct(ProductRequest request, StreamObserver<ProductResponse> responseObserver) {
ProductDTO product = productService.getProductById(request.getId());
ProductResponse response = ProductResponse.newBuilder()
.setId(product.getId())
.setName(product.getName())
.setStock(product.getStock())
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
Implémentation du Client
@Component
public class ProductGrpcClient {
private final ManagedChannel channel;
private final ProductServiceGrpc.ProductServiceBlockingStub blockingStub;
public ProductGrpcClient(@Value("${grpc.server.host}") String host,
@Value("${grpc.server.port}") int port) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.build();
blockingStub = ProductServiceGrpc.newBlockingStub(channel);
}
public ProductResponse getProduct(Long id) {
ProductRequest request = ProductRequest.newBuilder()
.setId(id)
.build();
return blockingStub.getProduct(request);
}
}
4. Communication avec Apache Kafka
Configuration
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
Configuration Kafka
spring:
kafka:
bootstrap-servers: localhost:9092
consumer:
group-id: product-group
auto-offset-reset: earliest
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
Implémentation du Producteur
@Component
@RequiredArgsConstructor
public class KafkaProducer {
private final KafkaTemplate<String, OrderEvent> kafkaTemplate;
public void sendOrderEvent(OrderEvent event) {
kafkaTemplate.send(
"order-events",
event.getOrderId().toString(),
event
);
}
}
Implémentation du Consommateur
@Component
@RequiredArgsConstructor
public class KafkaConsumer {
private final ProductService productService;
@KafkaListener(topics = "order-events", groupId = "product-group")
public void handleOrderEvent(OrderEvent event) {
switch (event.getType()) {
case ORDER_CREATED:
productService.updateStock(event.getProductId(), -event.getQuantity());
break;
case ORDER_CANCELLED:
productService.updateStock(event.getProductId(), event.getQuantity());
break;
}
}
}
5. Communication avec WebSocket
Configuration
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
Configuration WebSocket
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("*")
.withSockJS();
}
}
Implémentation du Service
@Service
@RequiredArgsConstructor
public class NotificationService {
private final SimpMessagingTemplate messagingTemplate;
public void sendStockUpdate(Long productId, int newStock) {
StockUpdate update = new StockUpdate(productId, newStock);
messagingTemplate.convertAndSend(
"/topic/stock-updates",
update
);
}
}
Client WebSocket
const socket = new SockJS('/ws');
const stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
stompClient.subscribe('/topic/stock-updates', function(update) {
const stockUpdate = JSON.parse(update.body);
updateUI(stockUpdate);
});
});
6. Patterns de Communication
1. Synchronous vs Asynchronous
Communication Synchrone
- REST avec OpenFeign
- gRPC
- Avantages :
- Simplicité
- Réponse immédiate
- Inconvénients :
- Couplage temporel
- Blocage des ressources
Communication Asynchrone
- RabbitMQ
- Kafka
- WebSocket
- Avantages :
- Découplage
- Scalabilité
- Résilience
- Inconvénients :
- Complexité
- Gestion des erreurs
2. Patterns de Communication
Request-Response
// REST
@GetMapping("/api/products/{id}")
public ProductDTO getProduct(@PathVariable Long id) {
return productService.getProduct(id);
}
// gRPC
rpc GetProduct (ProductRequest) returns (ProductResponse) {}
Event-Driven
// RabbitMQ
@RabbitListener(queues = "order-queue")
public void handleOrderCreatedEvent(OrderCreatedEvent event) {
// Traitement
}
// Kafka
@KafkaListener(topics = "order-events")
public void handleOrderEvent(OrderEvent event) {
// Traitement
}
Publish-Subscribe
// WebSocket
messagingTemplate.convertAndSend("/topic/stock-updates", update);
Exercices pratiques
-
Implémentation d’un système de notification
- Créez un service de notification
- Implémentez la communication avec WebSocket
- Ajoutez la gestion des erreurs
-
Système de commande asynchrone
- Créez un service de commande
- Implémentez la communication avec RabbitMQ
- Gérer les retries et les dead letters
-
Streaming de données
- Créez un service de monitoring
- Implémentez la communication avec Kafka
- Ajoutez le traitement en temps réel
Conclusion
Dans ce chapitre, nous avons exploré différentes stratégies de communication entre microservices :
- REST avec OpenFeign
- Messaging avec RabbitMQ
- Communication gRPC
- Communication avec Kafka
- WebSocket
Chaque approche a ses avantages et ses cas d’utilisation spécifiques. Le choix dépend des besoins de votre application en termes de :
- Performance
- Scalabilité
- Fiabilité
- Complexité
Dans le prochain chapitre, nous explorerons la découverte de services avec Eureka.
Commentaires
Les commentaires sont alimentés par GitHub Discussions
Connectez-vous avec GitHub pour participer à la discussion