Implémentation pratique de Kafka dans des microservices Spring Boot
Les développeurs de niveau intermédiaire à senior peuvent déployer rapidement un cluster Kafka en utilisant KRaft et l'intégrer avec quatre services Spring Boot pour une boutique en ligne. Le order-service accepte les commandes via REST API et publie un événement order-placed. Le inventory-service réserve le stock et génère des événements inventory-reserved ou inventory-rejected. Les services analytics-service et notification-service traitent ces événements de manière asynchrone.
Prérequis : Java, Spring Boot, Docker, Docker Compose, Postman. Dépendances : Spring for Apache Kafka, Spring Web.
Docker Compose pour le cluster Kafka
Déploiement de trois brokers Kafka 8.1.0 avec KRaft sans Zookeeper. Chaque broker assume à la fois les rôles de broker et de contrôleur. Kafka-UI sur le port 8086 pour surveiller les topics, partitions et groupes de consommateurs.
Créez docker-compose.yaml :
services:
kafka-0:
image: confluentinc/cp-kafka:8.1.0
container_name: kafka-0
hostname: kafka-0
ports:
- "29092:29092"
environment:
CLUSTER_ID: ZETVJENWRjaECDUEExP_eg
KAFKA_NODE_ID: 0
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_LISTENERS: INTERNAL://:9091,EXTERNAL://:29092,CONTROLLER://:9093
KAFKA_CONTROLLER_QUORUM_VOTERS: 0@kafka-0:9093,1@kafka-1:9093,2@kafka-2:9093
KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka-0:9091,EXTERNAL://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
# Similarly for kafka-1 (port 29093), kafka-2 (port 29094)
kafka-ui:
image: provectuslabs/kafka-ui:v0.7.2
container_name: kafka-ui
ports:
- "8086:8080"
environment:
KAFKA_CLUSTERS_0_NAME: local
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka-0:9091,kafka-1:9091,kafka-2:9091
DYNAMIC_CONFIG_ENABLED: true
Commande de démarrage : docker compose up -d. Le cluster est prêt à l'emploi avec 3 partitions et une réplication x3.
Configuration des services Spring Boot
Paramètres communs du producteur
Dans application.properties pour tous les services :
spring.kafka.bootstrap-servers=localhost:29092,localhost:29093,localhost:29094
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
Création programmatique des topics
Classe KafkaConfig dans le package config :
@Configuration
public class KafkaConfig {
@Bean
public NewTopic orderPlacedTopic() {
return TopicBuilder.name("order-placed")
.partitions(3)
.replicas(3)
.config(TopicConfig.RETENTION_MS_CONFIG, "86400000")
.config(TopicConfig.RETENTION_BYTES_CONFIG, "524288000")
.build();
}
}
Rétention : 24 heures, 500 Mo par topic. De même pour inventory-reserved, inventory-rejected dans inventory-service.
Implémentation du Order-Service (Producteur)
DTO et événements
public record OrderRequest(String email, String productName, Integer quantity) {}
public record OrderPlacedEvent(String orderId, String email, String productName, Integer quantity) {}
Logique métier
@Service
public class OrderService {
private final KafkaTemplate<String, OrderPlacedEvent> kafkaTemplate;
public OrderService(KafkaTemplate<String, OrderPlacedEvent> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
public String placeOrder(OrderRequest orderRequest) {
String orderId = UUID.randomUUID().toString();
OrderPlacedEvent event = new OrderPlacedEvent(orderId, orderRequest.email(),
orderRequest.productName(), orderRequest.quantity());
kafkaTemplate.send("order-placed", event);
return orderId;
}
}
Le contrôleur REST renvoie un 201 Created avec l'orderId instantanément, le traitement s'effectuant de manière asynchrone.
Inventory-Service : Producteur + Consommateur
Écoute order-placed, vérifie les niveaux de stock et publie inventory-reserved ou inventory-rejected. Nécessite @KafkaListener et un second KafkaTemplate.
Rôles des services :
- Producteur pur : order-service
- Consommateur pur : analytics-service, notification-service
- Producteur+Consommateur : inventory-service
Implémentation du consommateur (analytics, notification)
@KafkaListener(topics = "inventory-reserved")
public void handleInventoryReserved(InventoryReservedEvent event) {
// Analytics logic
}
Spring Kafka gère automatiquement les offsets, les groupes de consommateurs étant formés par le nom du service.
Test du flux
- POST
/ordersavec le JSON{ "email": "[email protected]", "productName": "laptop", "quantity": 1 } - Surveiller dans Kafka-UI : order-placed → inventory-reserved
- Les services analytics et notification reçoivent les événements en parallèle
Points clés :
- KRaft simplifie le déploiement sans Zookeeper
- 3 partitions + réplication x3 = tolérance aux pannes
- JsonSerializer pour la valeur, StringSerializer pour la clé
- Rétention 24h/500 Mo adaptée au développement
- KafkaTemplate abstrait l'API de bas niveau
— Editorial Team
Aucun commentaire pour le moment.