Dokumentversion 29.05.2026 · Ziel: Der heutige einzelne VPS soll bis zu 100 000 MAU tragen, ohne umzufallen, und die App soll zu gegebener Zeit nahtlos auf ein CDN umziehen.
| Metric | Wert | Source |
|---|---|---|
| MAU | 100,000 | das Ziel |
| DAU | 30,000 | 30 % der MAU, normal für eine Zweck-App |
| Gleichzeitige WS | 10 000 (Spitze 15 000) | ~10 % der MAU tagsüber, 15 % in der Spitze |
| Aktionen pro Tag | 90,000 | 3 Öffnungen oder Anrufe je Tagesnutzer |
| HTTP-API-Anfragen pro Sekunde (Durchschnitt) | 3-5 | überwiegend key_create, host_sync und crash_report |
| HTTP-API-Anfragen pro Sekunde (Spitze) | 30-50 | nach einem Massen-Release, das Nummern aktualisiert |
count=1 — ein einziger PHP-Prozess hält ALLE WebSocket-Verbindungen in den Arrays $hosts, $guests, $calls in-memory.File: HostService.kt:1424-1432. Heute syncPendingHostKeys() wird alle 60 s aufgerufen und trifft Api.keyCreate für jeden ausstehenden Schlüssel ohne jeden Backoff.
Speichern in Prefs per-localId: attempt_at_id und attempt_count_id. Backoff: 30 s → 60 s → 2 min → 5 min → 15 min → 30 min (Deckel). Bei Erfolg zurückgesetzt.
File: Vault.kt:213. Dieselbe Logik.
File: GuestConn.kt (5+ Stellen). Das neue parseNumbers mit dem vorherigen vergleichen, per Hash oder direkt. Sind sie gleich, nicht hochzählen: AppState.overridesVersion. Das beseitigt die Recompose-Wellen — 80 SharedPreferences-Lesevorgänge × 20 Karten — bei jeder WebSocket-Initialisierung.
In server.php case 'host_hello' / 'guest_hello': Hat derselbe device_id / user_key vor weniger als N Sekunden ein hello geschickt, die Verbindung schließen, ohne die Datenbank zu berühren. N = 5 s.
Schutz für den Fall, dass ein Client mit kaputter Logik hundert hellos pro Sekunde schickt.
In enqueueHostMsg: Hat dieser host_id bereits mehr als 200 Zeilen, die älteste löschen mit DELETE FROM pending_host_msgs WHERE host_id=? ORDER BY id ASC LIMIT 1. Schutz vor endlosem Wachstum der Warteschlange bei böswilliger Aktivität.
In _config.php:
$GLOBALS['apk_url'] = 'https://entrixy.com/entrixy.apk';
$GLOBALS['download_page_url'] = 'https://entrixy.com/download';
In api/version_check.php: 'download_url' => $GLOBALS['apk_url'].
Beim Umzug auf ein CDN ändert sich genau eine Zeile in _config.php to https://apk.entrixy.com/entrixy.apk (Cloudflare R2 mit eigener Domain). Ein App-Release ist nicht nötig.
Der Client prüft die APK-Signatur beim Herunterladen bereits (Debug-Keystore, siehe build.gradle.kts:23-29). Für ein CDN genügt das: Selbst wenn ein CDN-Knoten die Datei austauscht, passt die Signatur nicht und Android verweigert die Installation. Am Client ist nichts weiter zu tun.
count=1 Workerman hält rund 10 000 gleichzeitige WebSockets mühelos — server.php startet damit bereits in Zeile 40. Der erste Engpass wird die CPU-Zeit von PHP beim Spitzenaustausch: 10 000 Pongs pro Sekunde plus die Aktionen.
Today $hosts, $guests, $calls sind In-Memory-Arrays innerhalb eines Prozesses. Für mehrere Prozesse müssen sie nach Redis wandern:
Kommt eine Nachricht beim Worker W1 an, während der Empfänger auf W2 sitzt, wird sie über Redis pub/sub weitergereicht.
Effect: lineare Skalierung bis zur Kernanzahl des VPS. Auf vier Kernen sind das etwa 40 000 gleichzeitig.
Weniger flexibel und ohne Redis. Jeder Nutzer landet stets beim selben Worker. Es bricht jedoch zusammen, wenn Sender und Empfänger auf verschiedenen Workern liegen.
entrixy.apk.apk.entrixy.com → sie über das Cloudflare-CDN anbinden._config.php change $apk_url auf die neue.assembleRelease add r2 cp app-release.apk apk-bucket/entrixy.apk.