Caching
Das Zwischenspeichern von häufig angefragten Daten oder Berechnungsergebnissen, um wiederholte Anfragen schneller und günstiger zu beantworten.
Die zwei fundamentalen Performance-Metriken – Latenz misst wie schnell, Throughput misst wie viel. Oft ein Trade-off, beide wichtig für verschiedene Use Cases.
Latenz und Throughput sind die zwei fundamentalen Performance-Metriken – aber sie messen verschiedene Dinge und sind oft ein Trade-off.
Die Definitionen:
Latenz (Latency):
"Wie lange dauert EINE Anfrage?"
→ Gemessen in Millisekunden (ms)
→ Wichtig für User Experience
Throughput:
"Wie viele Anfragen pro Sekunde?"
→ Gemessen in Requests/Second (RPS)
→ Wichtig für Kapazität
Beispiel:
| System | Latenz | Throughput | Use Case |
|---|---|---|---|
| Chat-API | 50ms | 100 RPS | Interaktiv |
| Batch-ML | 500ms | 1000 RPS | Hintergrund |
| Datenbank | 5ms | 10.000 QPS | Beides wichtig |
Ohne Batching:
Request 1: ──────► 10ms
Request 2: ──────► 10ms
Request 3: ──────► 10ms
Latenz: 10ms, Throughput: 100 RPS
Mit Batching (3er Batches):
Request 1: ─┐
Request 2: ─┼─────────► 15ms (Batch)
Request 3: ─┘
Latenz: 15ms (+50%), Throughput: 200 RPS (+100%)
import numpy as np
def analyze_latencies(latencies):
return {
"p50": np.percentile(latencies, 50), # Median
"p90": np.percentile(latencies, 90), # 90% schneller
"p95": np.percentile(latencies, 95), # 95% schneller
"p99": np.percentile(latencies, 99), # 99% schneller
"p999": np.percentile(latencies, 99.9), # Worst case
"mean": np.mean(latencies),
"max": np.max(latencies),
}
# Beispiel
latencies = [10, 12, 11, 15, 10, 100, 11, 12, 10, 11] # ms
# p50: 11ms, p99: 100ms
# → Der Durchschnitt (20ms) ist irreführend!
import time
import asyncio
async def benchmark_throughput(client, duration_seconds=10):
start = time.time()
request_count = 0
while time.time() - start < duration_seconds:
await client.request()
request_count += 1
elapsed = time.time() - start
throughput = request_count / elapsed
return f"{throughput:.2f} requests/second"
L = λ × W
L = Anzahl gleichzeitiger Requests im System
λ = Throughput (Requests/Sekunde)
W = Durchschnittliche Latenz (Sekunden)
Beispiel:
- Throughput: 100 RPS
- Latenz: 50ms = 0.05s
- Gleichzeitige Requests: 100 × 0.05 = 5
| Ziel | Strategie |
|---|---|
| Niedrige Latenz | Caching, Edge Computing, weniger Hops |
| Hoher Throughput | Batching, Parallelisierung, Async |
| Beides | Horizontale Skalierung, Optimierter Code |
# Ohne Batching: Niedrige Latenz, niedriger Throughput
async def predict_single(model, input):
return model(input) # 10ms, 100 RPS
# Mit Batching: Höhere Latenz, höherer Throughput
class BatchPredictor:
def __init__(self, model, batch_size=32, max_wait_ms=50):
self.model = model
self.batch_size = batch_size
self.max_wait = max_wait_ms / 1000
self.queue = []
async def predict(self, input):
future = asyncio.Future()
self.queue.append((input, future))
if len(self.queue) >= self.batch_size:
await self._process_batch()
else:
await asyncio.sleep(self.max_wait)
if self.queue:
await self._process_batch()
return await future
async def _process_batch(self):
batch = self.queue[:self.batch_size]
self.queue = self.queue[self.batch_size:]
inputs = [item[0] for item in batch]
results = self.model(inputs) # Batch inference
for (_, future), result in zip(batch, results):
future.set_result(result) Latenz ist wie die Fahrzeit eines einzelnen Autos von A nach B. Throughput ist wie viele Autos pro Stunde die Straße passieren. Eine Autobahn hat hohen Throughput aber nicht unbedingt niedrige Latenz (Stau!).
Latenz: Zeit für eine einzelne Operation (ms)
Throughput: Operationen pro Zeiteinheit (req/s)
Oft Trade-off: Batching erhöht Throughput, aber auch Latenz
Real-Time APIs
Niedrige Latenz kritisch (Chat, Gaming)
Batch Processing
Hoher Throughput wichtiger als Latenz
ML Inference
Balance zwischen beiden für verschiedene Use Cases
Architektur
OLTP (Latenz) vs. OLAP (Throughput)
Kommt auf den Use Case an. Interaktive Apps: Latenz. Batch-Jobs: Throughput. Oft muss man beides optimieren, aber mit unterschiedlichen Prioritäten.
Batching erhöht Throughput (weniger Overhead pro Request), aber erhöht Latenz (warten bis Batch voll). Für ML-Inference oft sinnvoll, für Chat nicht.
99% der Requests sind schneller als dieser Wert. Wichtiger als Durchschnitt, weil er Ausreißer zeigt. P50 = Median, P99 = Worst Case für die meisten.