Architekturübersicht
Reva besteht aus sechs Komponenten, die sich Host-Ressourcen teilen:
+-----------+
Microsoft Teams ---->| Reva App |----> Ollama (GPU)
| FastAPI | - Router: llama3.2:3b
| Python | - Agent: qwen3:14b
+-----+-----+
|
+----------+----------+
| | |
+-----+--+ +----+---+ +----+---+
|PostgreSQL| | Redis | | MCP |
| pgvector | | cache | | servers|
+----------+ +--------+ +--------+
(Release, Jira)
Ressourcenverbrauchsprofil:
- GPU (Ollama): Der dominierende Engpass. Alle LLM-Inferenzen werden serialisiert über die GPU ausgeführt. Jede Benutzeranfrage erfordert 2–4 LLM-Aufrufe (1 Router-Klassifikation + 1–3 Agent-Schritte).
- CPU/RAM (Reva App): Leichtgewichtiger asynchroner Python-Prozess. Verbringt die meiste Zeit mit dem Warten auf GPU- und MCP-Antworten.
- CPU/RAM (MCP-Server): Zwei Sidecar-Container für API-Aufrufe an Digital.ai Release und Jira. Median-Latenz 63ms.
- CPU/RAM (PostgreSQL): Gesprächsverlauf und pgvector-Embeddings. Sub-Millisekunden-Abfragezeiten. War in Tests nie ein Engpass.
- CPU/RAM (Redis): Sitzungscache. Sub-Millisekunden-Latenz. Vernachlässigbarer Ressourcenverbrauch.
Komponentenanforderungen
Mindestressourcen pro Komponente für ein Single-Instance-Deployment:
| Komponente | CPU Request | CPU Limit | Memory Request | Memory Limit | Speicher | Hinweise |
|---|---|---|---|---|---|---|
| Reva App | 100m | 1000m | 256Mi | 1Gi | Minimal | Async I/O; ~791 MB RSS unter Last beobachtet |
| PostgreSQL | 100m | 500m | 256Mi | 512Mi | 10Gi PVC | pgvector-Index wächst mit Gesprächsanzahl |
| Redis | 50m | 200m | 64Mi | 128Mi | Ephemer | Nur Sitzungscache; Datenverlust ist unkritisch |
| Release MCP | 50m | 500m | 128Mi | 256Mi | Keiner | Sidecar; REST-Aufrufe an Release-Server |
| Jira MCP | 50m | 500m | 128Mi | 256Mi | Keiner | Sidecar; REST-Aufrufe an Jira-Instanz |
| Ollama | 1000m | — | 2Gi | — | 10–20Gi | Modelldateien auf Disk; GPU ist die eigentliche Ressource |
Gesamtminimum (ohne GPU): ~1,5 CPU-Kerne, ~3 GB RAM, ~20 GB Speicher. Die GPU ist nicht mit CPU-/Memory-Limits aufgeführt, da sie auf dem Host (oder einem dedizierten Knoten) läuft und VRAM als primäre Ressource nutzt.
GPU-Dimensionierung
Die GPU ist die wichtigste Kapazitätsentscheidung. Alle anderen Komponenten sind im Vergleich zur GPU günstig.
| GPU-VRAM | Beispiel-GPUs | Agent-Modell | NUM_PARALLEL | Gleichzeitige Benutzer | Antwortzeit (p50) | Geeignet? |
|---|---|---|---|---|---|---|
| 8 GB | RTX 5060, RTX 4060 | qwen3:8b | 1 | 1 | ~15s (geschätzt) | Nur Basisbetrieb |
| 12 GB | RTX 5070, RTX 4070 | qwen3:14b (knapp) | 1 | 1 | ~25s (geschätzt) | Grenzwertig; KV-Cache-Druck |
| 16 GB | RTX 5070 Ti, RTX 5080 | qwen3:14b | 1 | 1–2 | 22s (gemessen) | Getestete Basislinie |
| 24 GB | RTX 5090, A10, L4 | qwen3:14b | 2 | 3–5 | ~12s (projiziert) | Empfohlen |
| 48 GB | L40S, A6000 | qwen3:14b + vLLM | Batched | 10+ | ~8s (projiziert) | Mehrbenutzer-Produktion |
| 2x GPU | Beliebige Kombination | Dedizierter Router + Agent | 1 je | 3–5 | ~18s (projiziert) | Eliminiert Konkurrenz |
Wichtigste Ergebnisse aus Tests (RTX 5070 Ti 16GB)
- Einzelbenutzer: 22s Median End-to-End (4 Agent-Schritte, 1 Tool-Aufruf).
- Durchsatz-Obergrenze: 0,05 QPS (konstant unabhängig von Parallelität) = ~3 Anfragen/Min.
- Lineare Degradation: Jeder zusätzliche gleichzeitige Benutzer fügt ~20s Wartezeit hinzu, bedingt durch GPU-Queue-Serialisierung.
- 5 gleichzeitige Benutzer: 40% der Anfragen liefen beim 120s-Client-Timeout ab.
- NUM_PARALLEL=2 bei 16GB: 5x langsamer (110s vs. 22s). Das qwen3:14b-Modell belegt ~9 GB für Gewichte, sodass nur ~7 GB für KV-Cache verbleiben. Zwei parallele Sequenzen lösen CPU-Offloading aus.
Wann welche GPU-Stufe verwenden
- 8 GB: Proof of Concept oder persönliche Nutzung. Ein kleineres Modell (qwen3:8b) ist erforderlich. Reduzierte Tool-Calling-Genauigkeit zu erwarten.
- 16 GB: Kleines Team (< 20 Benutzer), leichte Nutzung. Akzeptabel, wenn die meisten Benutzer nur 1–2 Anfragen pro Tag senden.
- 24 GB: Mittleres Team (20–100 Benutzer), moderate Nutzung. Ermöglicht NUM_PARALLEL=2 ohne KV-Cache-Überlauf. Erste Stufe, auf der vLLM sinnvoll wird.
- 48 GB: Großes Deployment oder intensive Nutzung. vLLM-Continuous-Batching bietet nahezu lineares Durchsatz-Scaling bis 10+ gleichzeitige Benutzer.
Benutzer pro Instanz
„Gleichzeitige Benutzer“ unterscheidet sich von „Gesamtbenutzer.“ Die meisten Unternehmensbenutzer interagieren nur wenige Male täglich mit Reva. Die folgende Tabelle ordnet Gesamt-Teams-Benutzer der benötigten Infrastruktur zu, basierend auf einem gemessenen Durchsatz von ~3 Anfragen/Min. auf einer 16GB-GPU.
| Nutzungsmuster | Anfragen/Benutzer/Stunde | Peak gleichzeitig (gesch.) | Max. Benutzer (16GB) | Max. Benutzer (24GB) | Max. Benutzer (48GB) |
|---|---|---|---|---|---|
| Leicht | < 1 | 1 | 50–100 | 100–200 | 300+ |
| Mittel | 1–5 | 2–3 | 20–50 | 50–100 | 150–250 |
| Intensiv | 5–20 | 5–10 | 10–20 | 20–50 | 75–150 |
| Power-User | 20+ | 10+ | 5–10 | 10–20 | 50–75 |
So schätzen Sie Ihr Nutzungsmuster
- Zählen Sie Ihre Reva-berechtigten Benutzer (Release-Manager, Ops-Ingenieure usw.).
- Schätzen Sie die Spitzenstundenlast: Typischerweise sind 10–20% der Benutzer in der stärksten Stunde aktiv.
- Multiplizieren Sie aktive Benutzer mit durchschnittlichen Anfragen pro Stunde.
- Wenn die Spitzenanfragen/Minute 3 (16GB) oder 6 (24GB) übersteigt, benötigen Sie eine größere GPU oder mehrere Instanzen.
Beispiel: 40 Release-Manager, mittlere Nutzung (3 Anfragen/Stunde während der Spitze). Peak gleichzeitig = 40 × 0,15 × 3 / 60 = 0,3 Anfragen/Sek. = 18 Anfragen/Min. Dies übersteigt die 16GB-Kapazität (3 Anf./Min.) und die 24GB-Kapazität (~6 Anf./Min.). Lösung: 48GB-GPU oder mehrere Instanzen.
Skalierungsentscheidungsbaum
Verwenden Sie diesen Baum, wenn Antwortzeiten oder Timeouts auf Skalierungsbedarf hinweisen:
Skalierungsoptionen in Prioritätsreihenfolge
| Priorität | Maßnahme | Kosten | Erwartete Verbesserung | Einsatzzeitpunkt |
|---|---|---|---|---|
| 1 | GPU auf 24GB upgraden | 800–1500 $ | 2x gleichzeitige Kapazität | Erster Skalierungsschritt von 16GB |
| 2 | NUM_PARALLEL=2 aktivieren (24GB+) | Kostenlos | ~2x Durchsatz | Nach GPU-Upgrade |
| 3 | Schnelleres/kleineres Modell verwenden | Kostenlos | 30–50% Latenzreduktion | Wenn Genauigkeit mit qwen3:8b akzeptabel |
| 4 | Zweite GPU für Router hinzufügen | 200–500 $ | Eliminiert Router-/Agent-Konkurrenz | Wenn Router-Latenz > 2s unter Last |
| 5 | Auf vLLM wechseln (48GB+) | 3000–6000 $ (GPU) | 5–10x Durchsatz | Deployments mit hoher Parallelität |
| 6 | Mehrere Instanzen deployen | 2x Infrastruktur | Lineare Kapazitätsskalierung | Wenn Einzel-GPU-Skalierung ausgeschöpft |
| 7 | Cloud-LLM verwenden (Claude/OpenAI) | Pro-Token-Kosten | Unbegrenzte Skalierung | Siehe Kostenvergleich unten |
K8s-Ressourcenbeispiele
Produktionsgetestete Ressourcenspezifikationen aus den Kubernetes-Manifesten des Projekts.
Reva-Anwendungs-Pod (inkl. MCP-Sidecars)
apiVersion: apps/v1
kind: Deployment
metadata:
name: reva
namespace: reva
spec:
replicas: 1
template:
spec:
containers:
- name: reva
image: reva:latest
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 1Gi
- name: release-mcp
image: xebialabsearlyaccess/dai-release-mcp:25.3.0-beta.926
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
memory: 256Mi
- name: jira-mcp
image: ghcr.io/sooperset/mcp-atlassian:0.21.0
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
memory: 256Mi
PostgreSQL StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: reva
spec:
template:
spec:
containers:
- name: postgres
image: pgvector/pgvector:pg16
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 512Mi
volumeClaimTemplates:
- metadata:
name: pgdata
spec:
resources:
requests:
storage: 10Gi
Redis
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: reva
spec:
template:
spec:
containers:
- name: redis
image: redis:7-alpine
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
memory: 128Mi
Gesamtes Pod-Ressourcenbudget
| Ressource | Requests (Summe) | Limits (Summe) |
|---|---|---|
| CPU | 350m | (kein CPU-Limit) |
| Memory | 704Mi | 1,5Gi |
| Speicher | 10Gi (PostgreSQL PVC) | — |
Dies sind konservative Werte. Für Deployments mit erwarteter Dauerlast sollte das Reva-App-Memory-Limit auf 2Gi erhöht werden (beobachteter RSS von 791 MB unter Last mit Reserven für Spitzen).
Cloud-LLM-Vergleich
Wenn die lokale GPU-Kapazität nicht ausreicht, bieten Cloud-LLM-APIs unbegrenzte Skalierung zu Pro-Token-Kosten. Dieser Vergleich geht davon aus, dass das Ollama-Router-Modell (llama3.2:3b) weiterhin lokal läuft.
Kosten pro Anfrage (Schätzung)
Eine typische Reva-Anfrage umfasst ~4 LLM-Aufrufe mit insgesamt ca. 4.000 Eingabe-Tokens und 800 Ausgabe-Tokens.
| Anbieter | Modell | Eingabekosten | Ausgabekosten | Kosten/Anfrage | Kosten/1000 Anfragen |
|---|---|---|---|---|---|
| Lokal (Ollama) | qwen3:14b | 0 $ | 0 $ | 0 $ | 0 $ (nur GPU-Amortisation) |
| Anthropic | Claude Sonnet 4 | 3 $/M Eingabe | 15 $/M Ausgabe | ~0,024 $ | ~24 $ |
| Anthropic | Claude Haiku 3.5 | 0,80 $/M Eingabe | 4 $/M Ausgabe | ~0,006 $ | ~6 $ |
| OpenAI | GPT-4o | 2,50 $/M Eingabe | 10 $/M Ausgabe | ~0,018 $ | ~18 $ |
| OpenAI | GPT-4o-mini | 0,15 $/M Eingabe | 0,60 $/M Ausgabe | ~0,001 $ | ~1 $ |
Break-Even-Analyse
GPU-Amortisationskosten über 3 Jahre (typischer Enterprise-Hardware-Lebenszyklus):
| GPU | Anschaffungskosten | Monatliche Amortisation | Break-even vs. Claude Haiku | Break-even vs. GPT-4o-mini |
|---|---|---|---|---|
| RTX 5070 Ti 16GB | ~800 $ | ~22 $/Monat | ~3.700 Anfragen | ~22.000 Anfragen |
| RTX 5090 32GB | ~2.000 $ | ~56 $/Monat | ~9.300 Anfragen | ~56.000 Anfragen |
| L40S 48GB | ~6.000 $ | ~167 $/Monat | ~27.800 Anfragen | ~167.000 Anfragen |
Wann Cloud sinnvoll ist
- Weniger als 100 Anfragen/Tag und Sie möchten keine GPU beschaffen
- Burst-Kapazität benötigt, die über die lokale GPU hinausgeht
- Proof of Concept oder Testinstallationen
Wann lokale GPU sinnvoll ist
- Mehr als 100 Anfragen/Tag im Dauerbetrieb
- Anforderungen an Datensouveränität (keine Daten verlassen das Netzwerk)
- Planbare, feste monatliche Kosten gegenüber variablen Pro-Token-Abrechnungen bevorzugt
Monitoring für Kapazität
Reva stellt Metriken über GET /api/stats (JSON) und GET /api/metrics (Prometheus) bereit. Dies sind die kapazitätsrelevanten Metriken:
| Metrik | Quelle | Warnschwelle | Kritische Schwelle | Maßnahme |
|---|---|---|---|---|
response_time_p95_s |
/api/stats | > 30s | > 60s | GPU-Upgrade erforderlich |
response_time_p50_s |
/api/stats | > 20s | > 40s | Modell-/Konfigurations-Regression prüfen |
requests_per_minute |
/api/stats | Nähert sich 3 (16GB) | Dauerhaft am Limit | GPU skalieren oder Instanz hinzufügen |
active_sessions |
/api/stats | > 3 (16GB) | > 5 (16GB) | Benutzer werden Warteschlangen erleben |
llm.response_time_p50_s |
/api/stats | > 25s | > 50s | GPU-Konkurrenz oder Modellwechsel |
db_pool_checked_out |
/api/stats | > 20 (von 30 max.) | > 28 | pool_size erhöhen |
error_count |
/api/stats | Jede Zunahme | > 5% Fehlerrate | Logs untersuchen |
Prometheus-Alerting-Regeln (Beispiel)
groups:
- name: reva-capacity
rules:
- alert: RevaHighLatency
expr: reva_request_duration_seconds{quantile="0.95"} > 30
for: 5m
labels:
severity: warning
annotations:
summary: "Reva p95-Antwortzeit überschreitet 30s"
- alert: RevaVeryHighLatency
expr: reva_request_duration_seconds{quantile="0.95"} > 60
for: 5m
labels:
severity: critical
annotations:
summary: "Reva p95-Antwortzeit überschreitet 60s"
- alert: RevaHighErrorRate
expr: rate(reva_requests_total{status="error"}[5m]) / rate(reva_requests_total[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "Reva-Fehlerrate überschreitet 5%"
- alert: RevaDBPoolExhaustion
expr: reva_db_pool_checked_out / reva_db_pool_size > 0.9
for: 1m
labels:
severity: warning
annotations:
summary: "Datenbank-Connection-Pool > 90% ausgelastet"
Manueller Kapazitätscheck
Führen Sie dies regelmäßig oder nach Skalierungsänderungen aus:
# Schneller Kapazitäts-Snapshot
curl -s http://localhost:3978/api/stats | jq '{
response_p50: .request_performance.response_time_p50_s,
response_p95: .request_performance.response_time_p95_s,
rpm: .request_performance.requests_per_minute,
active_sessions: .conversations.active_sessions,
llm_p50: .llm.response_time_p50_s,
db_pool_used: .infrastructure.db_pool_checked_out,
db_pool_max: (.infrastructure.db_pool_size + 20),
process_rss_mb: (.infrastructure.process_rss_bytes / 1048576 | floor)
}'
Speicherplanung
PostgreSQL-Wachstum
PostgreSQL speichert Gesprächsverlauf, pgvector-Embeddings und Metadaten. Das Wachstum hängt vom Nutzungsvolumen ab.
| Datentyp | Größe pro Einheit | Wachstumstreiber |
|---|---|---|
| Gesprächsnachricht | ~2 KB | 1 Zeile pro Benutzernachricht + 1 Zeile pro Bot-Antwort |
| pgvector-Embedding | ~6 KB (1536 Dimensionen, float32) | 1 pro Gesprächsrunde (für Memory-Retrieval) |
| Sitzungsmetadaten | ~0,5 KB | 1 Zeile pro Gesprächssitzung |
Geschätztes monatliches Wachstum
| Nutzungslevel | Nachrichten/Monat | Speicherwachstum/Monat | 1-Jahres-Prognose |
|---|---|---|---|
| Leicht (20 Benutzer, 2 Anfragen/Tag) | ~1.200 | ~10 MB | ~120 MB |
| Mittel (50 Benutzer, 5 Anfragen/Tag) | ~7.500 | ~60 MB | ~720 MB |
| Intensiv (100 Benutzer, 10 Anfragen/Tag) | ~30.000 | ~250 MB | ~3 GB |
Die Standard-PVC-Größe von 10 Gi reicht für alle außer den intensivsten Deployments über mehrere Jahre. Berücksichtigen Sie täglich komprimierte Backups (~5–10% der DB-Größe pro Backup, 30-Tage-Aufbewahrung):
| DB-Größe | Backup-Größe (komprimiert) | 30-Tage-Aufbewahrung |
|---|---|---|
| 500 MB | ~50 MB | ~1,5 GB |
| 2 GB | ~200 MB | ~6 GB |
| 5 GB | ~500 MB | ~15 GB |
Ollama-Modellspeicher
Modelldateien werden auf dem Ollama-Host gespeichert (nicht im K8s-Cluster).
| Modell | Festplattengröße |
|---|---|
| llama3.2:3b (Router) | ~2 GB |
| qwen3:14b (Agent) | ~9 GB |
| nomic-embed-text (Embeddings) | ~0,3 GB |
| Gesamt | ~11 GB |
Planen Sie mindestens 20 GB für Ollama-Speicher ein, um Modell-Updates und zusätzliche Modelle unterzubringen.
Docker-Log-Speicher
Log-Rotation ist in docker-compose.yml konfiguriert:
| Service | Max. Größe pro Datei | Max. Dateien | Gesamt max. |
|---|---|---|---|
| Reva | 50 MB | 5 | 250 MB |
| PostgreSQL | 20 MB | 3 | 60 MB |
| Redis | 10 MB | 3 | 30 MB |
| Gesamt | 340 MB |