Der Performance-Pfad kombiniert parallele I/O-Aufrufe mit Bulkhead, Timeout, Rate Limit und Connection Pool. Ein Advisor trennt I/O-gebundene von CPU-gebundenen Workloads und begründet die Ausführungsstrategie.
1. Run8BDemoStartet verschiedene Lastprofile und zeigt erfolgreiche, gedrosselte und abgebrochene Aufrufe.
2. OrderViewServiceLädt Order-, Payment- und Inventory-Daten parallel und setzt daraus die Sicht zusammen.
3. BulkheadBegrenzt gleichzeitig laufende Aufrufe, damit eine Abhängigkeit nicht alle Ausführungskapazität bindet.
4. TimeoutPolicyBeendet Arbeit, die das definierte Zeitbudget überschreitet.
5. WindowRateLimiterBegrenzt die Anzahl akzeptierter Aufrufe pro Zeitfenster.
6. SimulatedConnectionPoolMacht sichtbar, dass virtuelle Threads externe Poolgrenzen nicht aufheben.
7. WorkloadClassifierUnterscheidet I/O- und CPU-Last als Grundlage der Laufzeitentscheidung.
8. PerformanceAdvisorLeitet aus Workload und Ressourcenengpässen eine konkrete PerformanceDecision ab.
9. Run8BTestRunnerPrüft Parallelität, Schutzmechanismen, Poolgrenzen und Beratungsergebnisse.
Rolle im AblaufLädt Order-, Payment- und Inventory-Daten parallel und setzt daraus die Sicht zusammen.
Im Lesepfad folgt Bulkhead: Begrenzt gleichzeitig laufende Aufrufe, damit eine Abhängigkeit nicht alle Ausführungskapazität bindet.
package com.example.run8b;
import java.time.Duration;
import java.util.concurrent.*;
// Pattern: Application Service - koordiniert Use Case, Ports und technische Schutzgrenzen.
public final class OrderViewService {
private final FakeOrderRepository orders;
private final FakePaymentClient payments;
private final FakeInventoryClient inventory;
private final Bulkhead paymentBulkhead;
private final Bulkhead inventoryBulkhead;
private final TimeoutPolicy timeout;
public OrderViewService(FakeOrderRepository orders, FakePaymentClient payments, FakeInventoryClient inventory,
Bulkhead paymentBulkhead, Bulkhead inventoryBulkhead, TimeoutPolicy timeout) {
this.orders = orders; this.payments = payments; this.inventory = inventory; this.paymentBulkhead = paymentBulkhead; this.inventoryBulkhead = inventoryBulkhead; this.timeout = timeout;
}
public OrderView build(OrderId id) {
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
Future<OrderData> order = executor.submit(() -> orders.load(id));
Future<PaymentData> payment = executor.submit(() -> paymentBulkhead.call(() -> payments.load(id)));
Future<InventoryData> stock = executor.submit(() -> inventoryBulkhead.call(() -> inventory.load(id)));
return new OrderView(timeout.get(order, "order"), timeout.get(payment, "payment"), timeout.get(stock, "inventory"), false);
}
}
public static OrderViewService demoService(MetricsRegistry metrics) {
SimulatedConnectionPool pool = new SimulatedConnectionPool(2, metrics);
return new OrderViewService(new FakeOrderRepository(pool), new FakePaymentClient(new WindowRateLimiter(10, Duration.ofSeconds(1).toMillis())), new FakeInventoryClient(), new Bulkhead("payment", 4, metrics), new Bulkhead("inventory", 4, metrics), new TimeoutPolicy(Duration.ofMillis(500)));
}
}
Rolle im AblaufPrüft Parallelität, Schutzmechanismen, Poolgrenzen und Beratungsergebnisse.
Damit ist der zentrale Pfad abgeschlossen; der Test-/Runner-Code und die vollständige Dateiliste darunter zeigen die übrigen Varianten.
package com.example.run8b;
import java.time.Duration;
public final class Run8BTestRunner {
public static void main(String[] args) {
buildsOrderViewWithVirtualThreads();
rejectsWhenBulkheadIsFull();
detectsRateLimit();
classifiesResourceBoundWorkload();
cpuChecksumIsStable();
System.out.println("RUN8B_TESTS_OK");
}
static void buildsOrderViewWithVirtualThreads() {
MetricsRegistry metrics = new MetricsRegistry();
OrderView view = OrderViewService.demoService(metrics).build(new OrderId("ORD-1"));
require(view.payment().authorized(), "payment should be authorized");
require(metrics.get("payment.accepted") == 1, "payment metric missing");
}
static void rejectsWhenBulkheadIsFull() {
MetricsRegistry metrics = new MetricsRegistry();
Bulkhead bulkhead = new Bulkhead("tiny", 1, metrics);
bulkhead.call(() -> "ok");
require(metrics.get("tiny.accepted") == 1, "accepted metric missing");
}
static void detectsRateLimit() {
WindowRateLimiter limiter = new WindowRateLimiter(1, Duration.ofSeconds(60).toMillis());
require(limiter.tryAcquire(), "first call allowed");
require(!limiter.tryAcquire(), "second call rejected");
}
static void classifiesResourceBoundWorkload() {
PerformanceDecision d = new PerformanceAdvisor().decide(true, true, false);
require(d.classifier() == WorkloadClassifier.RESOURCE_BOUND, "db pool workload must be resource bound");
}
static void cpuChecksumIsStable() {
long a = new CpuWorkload().checksum(1000);
long b = new CpuWorkload().checksum(1000);
require(a == b, "checksum must be deterministic");
}
static void require(boolean condition, String message) { if (!condition) throw new AssertionError(message); }
}