Dezentrale Prozessorchestrierung mit RabbitMQ: Eine Alternative zu Apache Camel
Ein System zur Verarbeitung großer Datenmengen aus FTP-Dateien und Kafka/RabbitMQ-Streams nutzt eine Microservices-Architektur mit über 40 Diensten. Zuvor wurden Verarbeitungsketten mit Apache Camel über Java DSL mit REST-Aufrufen von einem zentralen Dienst implementiert. Probleme umfassten Zustandsverlust bei Neustarts, Skalierungsbeschränkungen durch parallele Streams und Risiken bei Releases.
Eine neue RabbitMQ-Bibliothek mit Quorum-Queues ermöglicht dezentrales Management. Der Zustand wird im Broker gespeichert, und Prozesse setzen automatisch fort. Der Initialisierungsdienst skaliert horizontal.
Kernbibliotheks-Entitäten
Die Bibliothek enthält Klassen und Schnittstellen für Schritte, Routen und Executors:
- RouteStepInfo: Identifiziert einen Schritt in einer Route.
public class RouteStepInfo {
private final String routeName;
private final String stepId;
public RouteStepInfo(String routeName, String stepId) {
this.routeName = routeName;
this.stepId = stepId;
}
}
- StepExecutor: Schnittstelle für asynchrone/synchrone/entkoppelte Ausführung.
public interface StepExecutor {
String getStepName();
void runAsync(RouteStepInfo routeStepInfo, Long objectId);
void runSync(RouteStepInfo routeStepInfo, Long objectId);
void runDetached(RouteStepInfo routeStepInfo, Long objectId);
void appendListener(StepExecutionFinishedListener listener);
}
- StepExecutionFinishedListener: Callback für Schrittabschluss.
public interface StepExecutionFinishedListener {
void onStepExecutionFinished(RouteStepInfo routeStepInfo, Long objectId);
}
- RouteStep: Schritt mit ASYNC-, SYNC-, DETACHED-Modi.
public interface RouteStep {
String getRouteName();
String getStepId();
String getStepName();
ExecutionMode getExecutionMode();
void run(Long objectId);
void appendListener(StepExecutionFinishedListener listener);
enum ExecutionMode {
ASYNC,
SYNC,
DETACHED
}
}
- ExecutionRoute: Route als Liste von Schritten mit Indizes.
@Slf4j
public class ExecutionRoute {
@Getter
private final String routeName;
private final List<RouteStep> routeSteps;
private final Map<String, Integer> stepsIndex;
public ExecutionRoute(String routeName, List<RouteStep> routeSteps) {
this.routeName = routeName;
this.routeSteps = routeSteps;
this.stepsIndex = new HashMap<>();
for (int i = 0; i < routeSteps.size(); i++) {
stepsIndex.put(routeSteps.get(i).getStepId(), i);
}
}
}
Zusätzlich: RoutesConfigBuilder für Konfiguration, RouterConfigProvider für Routen, ProcessRouter als Listener und Executor.
Schrittausführungsmodi
Die Bibliothek unterstützt drei Modi:
- ASYNC: Sequentielle Hintergrundausführung, Fortsetzung nach Abschluss.
- SYNC: Blockierender Aufruf, Rückkehr nach gesamter Kette.
- DETACHED: Ausführung ohne Warten, sofortiges Fortfahren.
Kombinationen ermöglichen Verzweigung und Parallelität:
- Route 1: SYNC-Schritte 1→2→3.
- Route 2: ASYNC-Schritte 1→2→3, sofortige Rückkehr.
- Route 3: ASYNC mit DETACHED-Schritt 2.
- Route 5: Parallele Subroute Route 4.
Implementierung und Migration
Lasttests bestätigten Funktionalität. Migration erfolgt phasenweise: Ersetzen von Camel-Teilen mit A/B-Umschaltung. Bestehende Abhängigkeiten bleiben für Rollback erhalten.
Wichtige Punkte:
- Zustand in RabbitMQ gewährleistet Fortsetzung nach Neustarts.
- Horizontale Skalierung des Initialisierers.
- Transparente Konfiguration über Builder.
- Unterstützung für Verzweigung und Parallelität ohne zentralen Dienst.
Dieser Ansatz eignet sich für Systeme mit hohen Anforderungen an Zuverlässigkeit und Skalierbarkeit.
— Editorial Team
Noch keine Kommentare.