Praktyczna implementacja Kafka w mikrousługach na Spring Boot
Programiści na poziomie middle/senior mogą od razu uruchomić klaster Kafka na KRaft i zintegrować go z czterema usługami Spring Boot sklepu internetowego. Order-service przyjmuje zamówienia przez REST API, publikuje zdarzenie order-placed. Inventory-service rezerwuje stany magazynowe i generuje inventory-reserved lub inventory-rejected. Analytics-service i notification-service przetwarzają te zdarzenia asynchronicznie.
Wymagania: Java, Spring Boot, Docker, Docker Compose, Postman. Zależności: Spring for Apache Kafka, Spring Web.
Docker Compose dla klastra Kafka
Wdrożenie trzech brokerów Kafka 8.1.0 z KRaft bez Zookeeper. Każdy broker pełni role broker i controller. Kafka-UI na porcie 8086 do monitorowania topiców, partycji, grup konsumentów.
Utwórz 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
# Analogicznie dla 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
Polecenie uruchomienia: docker compose up -d. Klaster gotowy do obciążenia z 3 partycjami i replikacją x3.
Konfiguracja usług Spring Boot
Wspólne ustawienia producer
W application.properties dla wszystkich usług:
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
Tworzenie topiców programowo
Klasa KafkaConfig w pakiecie 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();
}
}
Retention: 24 godziny, 500MB na topic. Analogicznie dla inventory-reserved, inventory-rejected w inventory-service.
Implementacja order-service (Producer)
DTO i zdarzenia
public record OrderRequest(String email, String productName, Integer quantity) {}
public record OrderPlacedEvent(String orderId, String email, String productName, Integer quantity) {}
Logika biznesowa
@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;
}
}
Kontroler REST zwraca 201 Created z orderId natychmiast, przetwarzanie asynchroniczne.
Inventory-service: Producer + Consumer
Nasłuchuje order-placed, sprawdza stany magazynowe, publikuje inventory-reserved lub inventory-rejected. Wymaga @KafkaListener i drugiego KafkaTemplate.
Role usług:
- Pure Producer: order-service
- Pure Consumer: analytics-service, notification-service
- Producer+Consumer: inventory-service
Implementacja Consumer (analytics, notification)
@KafkaListener(topics = "inventory-reserved")
public void handleInventoryReserved(InventoryReservedEvent event) {
// Logika analityki
}
Spring Kafka automatycznie zarządza offsetami, grupy konsumentów formowane są po nazwie usługi.
Testowanie przepływu
- POST
/ordersz JSON{ "email": "[email protected]", "productName": "laptop", "quantity": 1 } - Monitorowanie w Kafka-UI: order-placed → inventory-reserved
- Analytics i notification otrzymują zdarzenia równolegle
Co ważne:
- KRaft upraszcza wdrożenie bez Zookeeper
- 3 partycje + replikacja x3 = odporność na awarie
- JsonSerializer dla value, StringSerializer dla key
- Retention 24h/500MB nadaje się do rozwoju
- KafkaTemplate abstrahuje low-level API
— Editorial Team
Brak komentarzy.