Files
BSN-Chatsystem/bsn-server-split-plan.md

262 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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, 3060s, 1 Kern)
├── Piper TTS (CPU-mittel, 13s)
├── ffmpeg Video-Thumbnails (CPU-mittel, 25s)
├── 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 | 3060s | ⚠️ 23 gleichzeitig |
| **Piper TTS** | 50% (1 Kern) | 200 MB | 13s | ✅ 45 |
| **ffmpeg Thumbnail** | 80% (1 Kern) | 100 MB | 25s | ⚠️ 23 |
| LLM API-Call | 0% | 20 MB | 25s | ✅ Beliebig |
### Kritischer Pfad: SPIEL Essen Messe
Während der Messe (4 Tage, ~10h/Tag) ist mit **Spitzen von 2050 parallelen Requests** zu rechnen.
Der aktuelle 4-Kern-Server würde bei 34 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: 810 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 | 50500 KB | < 5 ms |
| WhatsApp Audio (2 Min.) | 25 MB | ~40 ms |
| WhatsApp Video (1 Min.) | 550 MB | ~400 ms |
| WAV-Audio (TTS Output) | 100500 KB | < 5 ms |
| JPEG Thumbnail | 1050 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)
1. `language_server.py` schreiben — Flask-App mit `/transcribe`, `/speak`, `/thumbnail`, `/health`
2. Whisper/Piper/ffmpeg-Code aus `app.py` in `language_server.py` verschieben
3. Auf Server B deployen und testen
4. healthcheck einrichten
### Phase 2: Web Server umbauen (1h)
5. `whisperclient.py` schreiben — HTTP-Client für Language Server
6. In `app.py`: direkte Funktionsaufrufe ersetzen durch `whisperclient.transcribe(audio_path)`
7. Fallback: wenn Language Server nicht erreichbar → Submission als "Transkription ausstehend" markieren
### Phase 3: Testen (1h)
8. WhatsApp-Sprachnachricht senden → Transkription via Server B verifizieren
9. TTS via Server B verifizieren
10. Video-Thumbnail via Server B verifizieren
11. Lasttest: 10 parallele Sprachnachrichten
### Phase 4: Proxmox (Daniel)
12. Proxmox auf Server B installieren
13. VM mit 12 Kernen + 16 GB RAM für Language Server
14. SSH-Zugang für Basti
### Phase 5: Redundanz (optional)
15. Language Server auch auf Server C deployen
16. Web Server mit Failover: wenn B nicht antwortet → C anfragen
### Phase 6: Monitoring
17. Health-Checks via cron (alle 60s)
18. 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
```bash
# 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 = 810 parallele Transkriptionen
- Web-Server bleibt IMMER responsiv, egal wie viele Sprachnachrichten reinkommen
---
## Nächste Schritte
1. Daniel installiert Proxmox auf Server B
2. Daniel gibt SSH-Zugang
3. Basti deployt `language_server.py`
4. Basti baut `app.py` um
5. Integrationstest
6. Produktiv setzen