- Bis zu 50.000 Smartphones gleichzeitig im Stadion.
- Admin klickt im Dashboard → sofortige “Live”-Kontrolle (Farbwechsel / Muster / Gewinner grün).
- Akzeptable End-to-End-Latenz: ≤ 10 Sekunden (1 Minute ist zu viel).
- Ideal: gleichzeitige Wahrnehmung (“alle werden gelb/rot”), keine hörbaren/visuellen Asynchronitäten.
- PWA bevorzugt (kein nativer App-Zwang), funktioniert über WLAN und/oder LTE/5G.
- Gewinnerlogik: “alle Farbe X, aber einige wenige sind grün”.
- SSE und WebSockets sind beide “lange offene Verbindungen” (eine Connection pro Client).
→ Skalierung: möglich, aber Betrieb & Load-Balancing & Backpressure sind anspruchsvoll. - “Exakt gleichzeitig” ist über Mobilfunk/WLAN nicht garantierbar (Funk, QoS, Energiesparen, Browser Throttling, Paketverlust, Reconnects).
- Das eigentliche Problem ist nicht nur “50k Verbindungen halten”, sondern:
- wie schnell können 50k Clients die neue Instruktion sicher erhalten?
- wie synchron zeigen sie sie an (selbst wenn sie sie zu unterschiedlichen Zeiten empfangen)?
Kernidee: Alle Clients holen dieselbe, kleine JSON-Anweisung aus einem Cache.
Die Anweisung enthält einen effective_at-Zeitpunkt in der nahen Zukunft (z.B. now + 2s), damit Geräte trotz unterschiedlicher Empfangszeit synchron anzeigen.
Response ist für alle gleich, z.B.:
{ "version": 4711, "mode": "solid", "color": "yellow", "effective_at": 1736240000123, "winners": [] }{ "version": 4712, "mode": "solid", "color": "red", "effective_at": 1736240002123, "winners": [77, 666] }
Client-Loop (PWA):
- Polling z.B. alle 1s (adaptiv: 250–500ms nur während “Show”, sonst 10–30s).
- Wenn
versionneu: lokal “timer” setzen biseffective_at, dann Farbe umschalten. - Gewinner-ID lokal prüfen (eigene ID in winners? → grün, sonst Basisfarbe).
Warum das gut ist:
- Server-seitig minimaler Aufwand pro Request (kein per-user DB read).
- Caching skaliert brutal gut: 50k Clients können denselben Edge-Cache treffen.
- 10 Sekunden Latenz ist machbar: bei Polling 1s + Netzwerk + Cache-Hit.
- Synchronität entsteht über scheduled execution, nicht über “gleichzeitigen Versand”.
Wichtige technische Details:
- Client braucht eine “brauchbar korrekte” Uhr. Lösung: bei jedem Poll die Serverzeit mitschicken
und Client-Offset schätzen (server_now - client_now), geglättet. - Browser-Timer können im Hintergrund throttlen → die PWA muss “Screen on / im Vordergrund” sein (was bei “Handy hochhalten” meist gegeben ist).
Skalierungsrechnung (grob):
- 50k Clients bei 1s Polling → 50k req/s (nicht 10k).
Bei 5s Polling → 10k req/s. - ABER: Mit Edge-Caching sind das überwiegend Cache-Hits, Origin sieht viel weniger.
- “10 Sekunden max” spricht eher für 2–5s Polling + Zeitstempel.
Viele finden 2–5s “gleichzeitig genug”, wenn es visuell im Stadion passiert.
Empfohlene Ausgestaltung:
- “Show-Mode”: Polling 1–2s, sonst 10–30s.
- Responses klein halten (gzip/brotli), winners als kurze Liste oder Bloom/bitset nur falls nötig.
- Per-Device-ID nur für Gewinner; alles andere ist global.
Cloudflare-Nutzen hierbei:
- Sehr guter Fit für Caching + Edge + optional Workers/Durable Objects als “state holder”.
- Der “PR-Dschungel” ist egal: braucht nur “eine JSON-URL, die sehr gut cached”.
Machbarkeit: Mittel bis hoch (mit richtiger Infrastruktur), aber “gleichzeitig” bleibt trotzdem schwer.
Schwierigkeit: Hoch (Ops, Load-Balancing, Reconnect-Stürme, Backpressure, Observability).
Pro:
- Niedrigere Latenz “im Mittel” als Polling.
- “Push”-Charakter: Admin klickt, Server sendet.
Contra:
- 50k gleichzeitige offene Verbindungen sind machbar, aber: Betrieb ist anspruchsvoll.
- Synchronität ist weiterhin nicht garantiert (Nachrichten kommen nicht alle gleich an).
- Django “klassisch” (sync gunicorn) ungeeignet; async stack nötig.
Wann sinnvoll:
- Wenn ihr wirklich Patterns in hoher Frequenz (z.B. 10–20 Hz) fahren wollt.
- Oder wenn “Show Control” sehr interaktiv ist und Polling zu grob wirkt.
Machbarkeit: Hoch für “viele Verbindungen halten” + “State zentral”.
Schwierigkeit: Mittel (neue Plattform), dafür weniger eigene Ops.
Pro:
- Durable Object kann als “Single Source of Truth” für aktuellen Show-State dienen.
- Connections können “am Edge” enden; Origin entlastet.
- Preis/Skalierung potenziell attraktiv.
Contra:
- Neue Architektur + Vendor Lock-in.
- Sync/Simultanität bleibt trotzdem: auch CF kann Physik nicht aushebeln.
Sweet Spot:
- Kombi aus A + C: Durable Object hält State, Worker liefert gecachte JSON an alle.
Machbarkeit: Niedrig bis mittel, abhängig von OS/Browser, oft nicht “instant/guaranteed”.
Schwierigkeit: Mittel (VAPID, Subscriptions, Zustelllogik), Ergebnis unsicher.
Pro:
- Keine dauerhafte Verbindung.
- Funktioniert auch wenn App nicht aktiv ist (theoretisch).
Contra:
- Zustellung kann verzögert sein (OS entscheidet), im Stadion-Usecase riskant.
- UX: Permission-Hürden, evtl. nicht zuverlässig genug für “Live Show”.
Fazit: Für “Gewinner später informieren” ok, für “alle jetzt GELB” eher nein.
Machbarkeit: Potenziell sehr hoch im lokalen Netz, aber praktisch schwierig mit Smartphones/Browsers.
Schwierigkeit: Hoch (Netzdesign im Stadion + Client-Tech).
Pro:
- Sehr geringe Latenz im lokalen Netz.
- “Broadcast” ist konzeptionell passend.
Contra:
- Browser/PWA kann i.d.R. kein UDP Multicast.
- Stadion-WLAN muss wirklich professionell sein (AP-Planung, Roaming, Multicast-Handling).
- LTE/5G Teilnehmer wären außen vor.
Fazit: Eher nur mit nativer App + kontrollierter Netzumgebung.
Machbarkeit: Theoretisch passend, praktisch schwer zugänglich (Provider, Regulierung, Kosten).
Schwierigkeit: Sehr hoch (Partner/Provider).
Pro:
- “One-to-many” ist genau der Zweck.
Contra:
- Nicht “mal eben bauen”.
- Integrations-/Verfügbarkeitsfragen.
Fazit: Nur wenn ihr einen Telco-Partner habt und es ein großes Produkt wird.
Audio wurde im Chat verworfen (PA-Lärm, Mikrofon, Fragilität, Nebeneffekte).
Machbarkeit: Niedrig.
Fazit: Als “lustiger Hack” denkbar, als Produkt eher nein.
- Synchronität / Wahrnehmung
- Selbst mit Push kann es “Wellen” geben.
- Lösung: time-based execution (effective_at) + lokale Offset-Kalibrierung.
- Browser & Energiesparen
- Hintergrundtabs throttlen Timer/Netz.
- Lösung: Show nur im Vordergrund; Screen-On UX; ggf. “Wake Lock API”.
- Netzwerk im Stadion
- WLAN Überlast, Roaming, NAT, Paketverlust, Congestion.
- Lösung: POC vor Ort + ggf. “stadium WiFi required” als Produktentscheidung.
- Load Spikes
- Wenn 50k gleichzeitig reloaden/reconnecten (“thundering herd”).
- Lösung: Caching, jitter, exponential backoff, serverseitige Rate-Limits, pre-warming.
- Gewinnerdaten
- winners-Liste darf nicht riesig werden.
- Lösung: wenige Gewinner (ok). Bei vielen Gewinnern: segmentierte Listen oder Bloom/bitset.
- Security / Manipulation
- Clients dürfen nicht “Gewinner” faken.
- Lösung: Gewinner erst serverseitig verifizieren (z.B. QR-Code claim) oder signierte payloads.
- Minimaler Endpoint
/stateliefert gecachte JSON:version,effective_at,color,winners.
- Client-PWA:
- Polling-Loop (1–2s im Show-Mode), Offset-Schätzung, scheduled execution.
- UI: Vollbildfarbe, optional debug overlay (offset, last_version, RTT).
- Lasttest:
- Simulieren 10k–50k req/s (k6/locust), Cache-Hit-Rate messen.
- Stadion-naher Test:
- 10–30 Handys, unterschiedliche Modelle/Browser, WLAN+LTE, messen:
- Verteilung der “switch time” (p50/p95/p99).
- 10–30 Handys, unterschiedliche Modelle/Browser, WLAN+LTE, messen:
- Ergebnis-Kriterium:
- “Für Zuschauer wirkt es gleichzeitig” = z.B. p95 innerhalb 1–2s Fenster.
- Ohne offene Verbindungen ist Polling + Edge-Caching + Zeitstempel die robusteste Best-Practice, die mit PWA realistisch funktioniert und die 10s-Anforderung treffen kann.
- WebSockets/SSE sind möglich, aber erhöhen Ops-Komplexität und lösen “Synchronität” nicht automatisch.
- Cloudflare kann helfen, vor allem als Caching/Edge und optional als State-Hub (Durable Objects).