Zurück zur Startseite

Kafka KRaft Praxis Spring Boot Mikroservices

Praktischer Leitfaden zur Bereitstellung eines Kafka-Clusters auf KRaft mit Integration in Spring Boot-Mikroservices. Vollständige Online-Shop-Architektur mit Producer/Consumer-Rollen, docker-compose-Konfiguration, programmatische Topic-Erstellung.

Kafka in der Praxis: KRaft-Cluster + Java-Mikroservices
Advertisement 728x90

Praktische Kafka-Implementierung in Spring Boot Microservices

Mittel- bis Senior-Entwickler können schnell einen Kafka-Cluster mit KRaft bereitstellen und ihn mit vier Spring Boot-Services für einen Online-Shop integrieren. Der order-service nimmt Bestellungen über eine REST API entgegen und veröffentlicht ein order-placed-Event. Der inventory-service reserviert Lagerbestände und erzeugt inventory-reserved- oder inventory-rejected-Events. Die analytics-service und notification-service verarbeiten diese Events asynchron.

Anforderungen: Java, Spring Boot, Docker, Docker Compose, Postman. Abhängigkeiten: Spring for Apache Kafka, Spring Web.

Docker Compose für Kafka-Cluster

Bereitstellung von drei Kafka 8.1.0-Brokern mit KRaft ohne Zookeeper. Jeder Broker übernimmt Broker- und Controller-Rollen. Kafka-UI auf Port 8086 zur Überwachung von Topics, Partitionen und Consumer Groups.

Google AdInline article slot

Erstellen Sie 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

Startbefehl: docker compose up -d. Der Cluster ist mit 3 Partitionen und x3-Replikation belastbar.

Konfiguration der Spring Boot Services

Gemeinsame Producer-Einstellungen

In application.properties für alle Services:

Google AdInline article slot
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

Programmatische Topic-Erstellung

KafkaConfig-Klasse im config-Paket:

@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 Stunden, 500 MB pro Topic. Ähnlich für inventory-reserved, inventory-rejected im inventory-service.

Order-Service-Implementierung (Producer)

DTOs und Events

public record OrderRequest(String email, String productName, Integer quantity) {}

public record OrderPlacedEvent(String orderId, String email, String productName, Integer quantity) {}

Geschäftslogik

@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;
    }
}

Der REST-Controller gibt sofort 201 Created mit der orderId zurück, die Verarbeitung erfolgt asynchron.

Google AdInline article slot

Inventory-Service: Producer + Consumer

Hört auf order-placed, prüft Lagerbestände und veröffentlicht inventory-reserved oder inventory-rejected. Erfordert @KafkaListener und eine zweite KafkaTemplate.

Service-Rollen:

  • Reiner Producer: order-service
  • Reiner Consumer: analytics-service, notification-service
  • Producer+Consumer: inventory-service

Consumer-Implementierung (analytics, notification)

@KafkaListener(topics = "inventory-reserved")
public void handleInventoryReserved(InventoryReservedEvent event) {
    // Analytics logic
}

Spring Kafka verwaltet Offsets automatisch, Consumer Groups werden durch den Service-Namen gebildet.

Testen des Flows

  • POST /orders mit JSON { "email": "[email protected]", "productName": "laptop", "quantity": 1 }
  • In Kafka-UI überwachen: order-placed → inventory-reserved
  • Analytics und notification erhalten Events parallel

Wichtige Punkte:

  • KRaft vereinfacht die Bereitstellung ohne Zookeeper
  • 3 Partitionen + x3 Replikation = Ausfallsicherheit
  • JsonSerializer für Value, StringSerializer für Key
  • 24h/500MB Retention geeignet für Entwicklung
  • KafkaTemplate abstrahiert die Low-Level-API

— Editorial Team

Advertisement 728x90

Weiterlesen