9.3 KiB
9.3 KiB
BSN Server-Architektur — Split-Plan
Stand: 18.06.2026 | Autor: Basti (Chef vom Dienst)
Status: Planungsphase — noch nicht umgesetzt
Ziel
Das BSN-Chatsystem von einem Monolithen auf zwei spezialisierte Dienste aufteilen:
| Server | Rolle | Optimiert für |
|---|---|---|
| Server A (aktuell, 4C/8GB) | Web-Frontend + Datenbank | I/O, HTTP-Requests |
| Server B (lokal, 24C/32GB) | Sprachverarbeitung | CPU, parallele Jobs |
Ist-Analyse
Aktueller Monolith (Port 5002)
app.py (Flask) — EIN Prozess, alles drin:
├── WhatsApp Webhook (I/O-leicht)
├── Telegram Webhook (I/O-leicht)
├── Public Frontend (I/O-leicht)
├── Admin Dashboard (I/O-leicht)
├── faster-whisper Transkription (CPU-schwer, 30–60s, 1 Kern)
├── Piper TTS (CPU-mittel, 1–3s)
├── ffmpeg Video-Thumbnails (CPU-mittel, 2–5s)
├── DeepSeek LLM-Calls (Netzwerk, kein CPU-Problem)
└── SQLite DB (I/O)
Ressourcen-Profil pro Aufgabe
| Aufgabe | CPU | RAM | Dauer | Parallelfähig |
|---|---|---|---|---|
| WhatsApp-Request | <1% | 5 MB | 50ms | ✅ Beliebig |
| Frontend-Rendering | 2% | 10 MB | 100ms | ✅ Beliebig |
| Whisper Transkription | 100% (1 Kern) | 1,5 GB | 30–60s | ⚠️ 2–3 gleichzeitig |
| Piper TTS | 50% (1 Kern) | 200 MB | 1–3s | ✅ 4–5 |
| ffmpeg Thumbnail | 80% (1 Kern) | 100 MB | 2–5s | ⚠️ 2–3 |
| LLM API-Call | 0% | 20 MB | 2–5s | ✅ Beliebig |
Kritischer Pfad: SPIEL Essen Messe
Während der Messe (4 Tage, ~10h/Tag) ist mit Spitzen von 20–50 parallelen Requests zu rechnen.
Der aktuelle 4-Kern-Server würde bei 3–4 gleichzeitigen Transkriptionen alle Kerne blockieren — Web-Requests würden timeouten.
Ziel-Architektur
┌─────────────────────────────────────────────────────┐
│ Server A — "Web & Data" │
│ 4 Kerne, 8 GB RAM │
│ Port 5002 (intern) │
│ │
│ Flask (app.py), schlank: │
│ ├── WhatsApp/Telegram Webhook │
│ ├── Public Frontend + Admin │
│ ├── SQLite (bsn_intake.db) │
│ ├── DeepSeek LLM-Calls │
│ └── HTTP-Client → Server B │
│ │
│ NUTZT: whisperclient.py (sendet Audio an Server B) │
└──────────────────────┬──────────────────────────────┘
│
HTTP (lokal, <1ms Latenz)
POST /transcribe {audio_file} → {text}
POST /speak {text} → {audio_file}
POST /thumbnail {video_file} → {thumbnail}
│
┌──────────────────────▼──────────────────────────────┐
│ Server B — "Language Processor" │
│ 24 Kerne, 32 GB RAM (lokal) │
│ Port 5003 (intern) │
│ │
│ Flask/FastAPI (language_server.py): │
│ ├── POST /transcribe │
│ │ └── faster-whisper 'base' model │
│ ├── POST /speak │
│ │ └── Piper TTS (de_DE-thorsten-medium) │
│ ├── POST /thumbnail │
│ │ └── ffmpeg -ss 1 -vframes 1 │
│ └── GET /health │
│ │
│ Worker-Pool: 8–10 parallele Transkriptionen │
│ RAM: 1,5 GB pro Whisper-Instanz ≈ 15 GB nutzbar │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ Server C — "Fallback & Test" │
│ 24 Kerne, 32 GB RAM (lokal) │
│ │
│ Optional: │
│ ├── Redundanz: Failover wenn Server B ausfällt │
│ ├── Testumgebung: Staging für neue Features │
│ └── Proxmox-Host: mehrere isolierte VMs │
└─────────────────────────────────────────────────────┘
API-Spezifikation (Server A ↔ Server B)
POST /transcribe
Request: multipart/form-data
file: audio.ogg (WhatsApp voice memo)
Response: 200 JSON
{
"ok": true,
"text": "Transkribierter deutscher Text...",
"duration_seconds": 12.5,
"processing_time_ms": 3420
}
Fehler: { "ok": false, "error": "..." }
POST /speak
Request: JSON
{
"text": "Hallo Daniel, hier ist deine Antwort.",
"voice": "de_DE-thorsten-medium" // optional, default
}
Response: 200 audio/wav
(binary WAV data)
Fehler: { "ok": false, "error": "..." }
POST /thumbnail
Request: multipart/form-data
file: video.mp4
Response: 200 image/jpeg
(binary JPEG, 320px wide)
Fehler: { "ok": false, "error": "..." }
GET /health
Response: 200 JSON
{
"ok": true,
"workers_busy": 2,
"workers_available": 8,
"uptime_seconds": 86400
}
Dateigrößen & Netzwerk
| Medientyp | Typische Größe | Übertragung (1 Gbit/s lokal) |
|---|---|---|
| WhatsApp Sprachnachricht | 50–500 KB | < 5 ms |
| WhatsApp Audio (2 Min.) | 2–5 MB | ~40 ms |
| WhatsApp Video (1 Min.) | 5–50 MB | ~400 ms |
| WAV-Audio (TTS Output) | 100–500 KB | < 5 ms |
| JPEG Thumbnail | 10–50 KB | < 1 ms |
Fazit: Dateigrößen sind kein Bottleneck. Selbst 50-MB-Videos gehen in <500ms über das lokale Netz.
Migrationsplan (6 Schritte)
Phase 1: Language Server extrahieren (2h)
language_server.pyschreiben — Flask-App mit/transcribe,/speak,/thumbnail,/health- Whisper/Piper/ffmpeg-Code aus
app.pyinlanguage_server.pyverschieben - Auf Server B deployen und testen
- healthcheck einrichten
Phase 2: Web Server umbauen (1h)
whisperclient.pyschreiben — HTTP-Client für Language Server- In
app.py: direkte Funktionsaufrufe ersetzen durchwhisperclient.transcribe(audio_path) - Fallback: wenn Language Server nicht erreichbar → Submission als "Transkription ausstehend" markieren
Phase 3: Testen (1h)
- WhatsApp-Sprachnachricht senden → Transkription via Server B verifizieren
- TTS via Server B verifizieren
- Video-Thumbnail via Server B verifizieren
- Lasttest: 10 parallele Sprachnachrichten
Phase 4: Proxmox (Daniel)
- Proxmox auf Server B installieren
- VM mit 12 Kernen + 16 GB RAM für Language Server
- SSH-Zugang für Basti
Phase 5: Redundanz (optional)
- Language Server auch auf Server C deployen
- Web Server mit Failover: wenn B nicht antwortet → C anfragen
Phase 6: Monitoring
- Health-Checks via cron (alle 60s)
- Alert an Telegram wenn Language Server down
Voraussetzungen
Was Daniel bereitstellen muss
- Server B: Proxmox installiert, VM bereit
- Server B: SSH-Zugang für Basti
- Server B: Linux (Debian/Ubuntu), Python 3.11+
- Lokales Netzwerk: Server A kann Server B erreichen (ping, HTTP)
Was auf Server B installiert wird
# System
apt install python3 python3-pip python3-venv ffmpeg espeak-ng
# Python
pip install faster-whisper flask requests
# Piper TTS (pre-built binary)
# Voices: de_DE-thorsten-medium.onnx (~61 MB)
Risiken & Fallbacks
| Risiko | Eintritts-WSK | Fallback |
|---|---|---|
| Server B nicht erreichbar | Niedrig (lokales Netz) | Submission markiert als "Transkription ausstehend", retry in 30s |
| Whisper-Modell zu langsam | Niedrig (24 Kerne) | Kleinere tiny-Variante laden |
| RAM voll (zu viele parallele Jobs) | Mittel (unter Last) | Worker-Pool begrenzen, Queue |
| Piper TTS fehlende Library | Niedrig | LD_LIBRARY_PATH + ESPEAK_DATA_PATH gesetzt |
Kosten-Nutzen
Vor dem Split (aktuell):
- 4-Kern-Server: Web + Transkription + TTS = alles in einem
- SPIEL Essen: 3 parallele Transkriptionen = alle Kerne blockiert = Web timeouts
Nach dem Split:
- 4-Kern-Server: NUR Web = ~100 gleichzeitige Requests möglich
- 24-Kern-Server: NUR Sprache = 8–10 parallele Transkriptionen
- Web-Server bleibt IMMER responsiv, egal wie viele Sprachnachrichten reinkommen
Nächste Schritte
- Daniel installiert Proxmox auf Server B
- Daniel gibt SSH-Zugang
- Basti deployt
language_server.py - Basti baut
app.pyum - Integrationstest
- Produktiv setzen