MAISON CODE .
/ Backend · Realtime · WebSockets · Analytics · UX

Echtzeit-Dashboards: Engineering Due Diligence

Warum die Schaltfläche „Aktualisieren“ veraltet ist. Ein technischer Leitfaden zu Server-Sent Events (SSE), WebSockets und dem C10K-Problem.

AB
Alex B.
Echtzeit-Dashboards: Engineering Due Diligence

Es ist Black Friday. Die Verwendung findet im „War Room“ statt. Der CEO fragt: „Wie viel Umsatz haben wir in den letzten 10 Minuten gemacht?“ Sie klicken auf „Aktualisieren“. Die Datenbankabfrage dauert 15 Sekunden. Die Seite wird geladen. „50.000 €.“ Wenn Sie es sagen, ist die Zahl falsch.

Im modernen Handel sind statische Daten tot. Lagerumzüge. Preise ändern sich. Verkehrsspitzen. Echtzeit-Dashboards sind nicht nur ein „nice to have“ visuelles Spielzeug; Sie sind geschäftskritische Einsatzwerkzeuge. Aber sie richtig zu entwickeln – für Tausende von gleichzeitigen Benutzern, ohne Ihre Datenbank zu zerstören – ist eine Herausforderung für verteilte Systeme.

Bei Maison Code Paris bauen wir „Mission Control“-Schnittstellen, die sich lebendig anfühlen. So machen wir es, ohne die Server zum Schmelzen zu bringen.

Warum Maison Code darüber spricht

Bei Maison Code Paris fungieren wir als das architektonische Gewissen unserer Kunden. Wir übernehmen oft „moderne“ Stacks, die ohne grundlegendes Verständnis für Skalierung gebaut wurden.

Wir diskutieren dieses Thema, weil es einen kritischen Wendepunkt in der technischen Reife darstellt. Die korrekte Implementierung unterscheidet ein fragiles MVP von einer widerstandsfähigen Plattform auf Unternehmensniveau.

Der Protokollkampf: Polling vs. SSE vs. WebSockets

Die erste Entscheidung für einen effizienten Datentransport.

1. Umfragen (Der naive Ansatz)

setInterval(() => fetch('/api/sales'), 5000);

  • Vorteile: Einfach. Funktioniert auf jedem Server (PHP, Node, Python).
  • Nachteile:
    • Latenz: Durchschnittliche Verzögerung von 2,5 Sekunden.
    • Verschwendung: 90 % der Anfragen geben „Keine Änderung“ zurück. Sie hämmern Ihre DB umsonst.
    • Batterie: Hält das Mobilfunkgerät aktiv.

2. WebSockets (die bidirektionale Pipe)

Eine dauerhafte TCP-Verbindung.

  • Vorteile: Extrem schnell. Bidirektional (Client kann „Ich tippe“ senden).
  • Nachteile:
    • Firewalls: Unternehmens-Proxys blockieren häufig Nicht-HTTP-Verkehr.
    • Statefulness: Die Skalierung ist schwierig. Sie benötigen Sticky Sessions oder ein Redis-Backend.
    • Overkill: Ein Dashboard ist normalerweise schreibgeschützt.

3. Vom Server gesendete Ereignisse (SSE) (Der Goldstandard)

Standard-HTTP-Verbindung, aber der Server hält sie offen und streamt Text. „Inhaltstyp: Text/Ereignisstream“.

  • Vorteile:
    • HTTP-kompatibel: Funktioniert über Standard-Load-Balancer/Proxys.
    • Auto-Reconnect: Der Browser verarbeitet Wiederholungsversuche automatisch.
    • Leichtgewicht: Nur einfache Textnachrichten.
  • Nachteile: Nur in eine Richtung (Server -> Client).

Bei Dashboards ist SSE der technische Gewinner.

Architektur: Der Eventbus

Sie können nicht einfach von der Datenbank zum Client streamen. Wenn Sie 5.000 Clients haben und jedes Mal, wenn sich eine Zeile ändert, ein „SELECT sum(total) FROMorders“ ausführen, stirbt PostgreSQL ab.

Sie benötigen eine Event-Bus-Architektur.

  1. Ingest: Webhook erstellen -> API bestellen.
  2. Veröffentlichen: API -> Redis Pub/Sub („channel: sales“).
  3. Fan-Out: Der SSE-Server abonniert Redis.
  4. Broadcast: Wenn Redis eine Nachricht sendet, durchläuft der SSE-Server die verbundenen Clients und schreibt in deren Streams.

Code: Der Remix/Node.js-Stream

In einem modernen Framework wie Remix oder Next.js App Router ist Streaming nativ.

„Typoskript // app/routes/api.stream.ts im Remix import { eventStream } aus „remix-utils/sse/server“; import { redis } from „~/lib/redis“;

Asynchronen Funktionslader exportieren ({ request }: LoaderFunctionArgs) { return eventStream(request.signal, function setup(send) { const channel = “dashboard-updates”;

const listener = (Nachricht: string) => {
  send({ event: "update", data: message });
};

const subscriber = redis.duplicate();
subscriber.subscribe(channel);
subscriber.on("message", (chan, msg) => {
  if (chan === Kanal) listener(msg);
});

Rückgabefunktion cleanup() {
  subscriber.unsubscribe(channel);
  subscriber.quit();
};

}); } „

Die Herausforderungen der Konnektivität

1. Das C10K-Problem (Skalierung)

Standard-Node.js kann ca. 10.000 gleichzeitige Verbindungen verarbeiten. Server wie Apache/PHP kämpfen mit Hunderten. Wenn Sie 100.000 verbundene Benutzer benötigen (z. B. bei einem riesigen Flash-Sale-Countdown), können Sie keinen Standard-Einzelserver verwenden. Lösung:

  • Horizontale Skalierung: 10 Server hinter einem Load Balancer.
  • Redis-Backplane: Jeder Server abonniert Redis. Wenn also Server A veröffentlicht, empfängt Server B es und sendet es an Benutzer B.
  • Managed Services: Für extreme Skalierung auf Pusher oder Supabase Realtime auslagern. Sie verwalten die Socket-Schicht.

2. Die donnernde Herde (Wiederverbindung)

Sie stellen eine neue Version des Dashboards bereit. Der Server wird neu gestartet. 5.000 Kunden trennen sich. 5.000 Clients versuchen sofort um genau 10:00:01 Uhr, die Verbindung wiederherzustellen. Ihre CPU steigt auf 100 %. Der Server stürzt ab. Clients versuchen es erneut. Schleife des Todes. Lösung: Jitter. Der Client sollte „random(0, 5000)“ Millisekunden warten, bevor er die Verbindung wiederherstellt. Die native SSE-Implementierung des Browsers verfügt über einen grundlegenden Backoff, die benutzerdefinierte WebSocket-Logik übersieht dies jedoch häufig.

3. Beschränkungen für Betriebssystem-Dateideskriptoren

Ein Linux-Server hat ein Standardlimit von 1024 geöffneten Dateien (Verbindungen). Wenn Sie 10.000 Benutzer möchten, MÜSSEN Sie „/etc/security/limits.conf“ bearbeiten. * soft nofile 100000 * hard nofile 100000 Wenn Sie dies vergessen, stürzt Ihr Node.js-Server mit „EMFILE“-Fehlern bei Benutzer Nr. 1025 ab.

Staatsversöhnung: Die Kluft

Der Benutzer befindet sich in einem Eisenbahntunnel. 10:00:00 – Benutzer online. Gesamt: 100 €. 10:00:05 – Tunnel. Benutzer offline. 10:00:06 – Server pusht Event „Neue Bestellung +50 €“. Der Gesamtbetrag beträgt jetzt 150 €. 10:00:10 – Tunnel endet. Benutzer verbindet sich erneut.

Der Benutzer geht davon aus, dass die Gesamtsumme 100 € beträgt. Sie haben die Veranstaltung verpasst. Der Staat driftet.

Fix: Last-Event-ID.

  1. Jedes Ereignis hat eine ID (Sequenznummer oder Zeitstempel).
  2. Der Browser speichert die zuletzt gesehene ID.
  3. Bei erneuter Verbindung sendet der Browser „Last-Event-ID: 105“.
  4. Der Server überprüft seinen Puffer. „Ah, der Kunde ist im Rückstand. Hier sind die Ereignisse 106, 107, 108.“

Oder einfachere Strategie: StaleCheck. Bei jeder erneuten Verbindung löst das Frontend einen Standard-HTTP-Abruf (‘/api/current-total’) aus, um die Baseline neu zu synchronisieren.

UX: Den Puls visualisieren

Echtzeitdaten erzeugen „visuelles Rauschen“. Wenn Sie 10 Artikel pro Sekunde verkaufen und die Zahl 10 Mal pro Sekunde aktualisieren, kann der Benutzer sie nicht lesen. Es ist nur eine Unschärfe.

Drosselaktualisierungen: Beschränken Sie die Neugestaltung der Benutzeroberfläche auf einmal alle 500 ms. Sammeln Sie die Änderungen in einem Puffer. „Puffer = +10, +5, +20“. Flush -> Benutzeroberfläche aktualisieren „+35“.

Animation: Verwenden Sie „framer-motion“ oder „react-spring“, um die Zahl zu animieren. „100“ -> „135“. Der Benutzer sieht, wie sich die Zahlen aufrollen (wie bei einer Zapfsäule). Dies vermittelt „Geschwindigkeit“ und „Aktivität“ viel besser als ein statischer Sprung.

„tsx function AnimatedNumber({ value }) { const { Zahl } = useSpring({ von: { Zahl: 0 }, Zahl: Wert, Verzögerung: 200, config: { Masse: 1, Spannung: 20, Reibung: 10 }, });

return <animated.span>{number.to((n) => n.toFixed(0))}</animated.span>; } „

10. Sicherheit: Rollenbasierte Zugriffskontrolle (RBAC) für Streams

Standard-HTTP-Auth validiert die Anfrage. Aber wie verhindern Sie, dass ein „Store Manager“ die Verkaufsereignisse des „Global Admin“ mithört, sobald der Socket geöffnet ist? Kanalbereichsbestimmung.

  1. Der Benutzer stellt eine Verbindung mit JWT her.
  2. Server dekodiert JWT -> „role: manager“, „store_id: 12“.
  3. Der Kunde beantragt ein Abonnement für „sales-global“.
  4. Serverlogik: if (role !== 'admin') throw Forbidden.
  5. Serverlogik: „Nur redis.subscribe(‘sales-store-12’) zulassen“.

11. Datengranularität: Tick vs. Aggregat

Sollten Sie für jede 5-Euro-Bestellung ein Ereignis ausgeben? Wenn Sie 100 Bestellungen/Sek. haben, sieht Ihr Dashboard wie ein Stroboskoplicht aus. Aggregationsstrategie:

  1. Raw Stream: Interne Verwendung/Debugging.
  2. Gedrosselter Stream (Benutzeroberfläche): Alle 1 Sekunde aggregieren.
    • { Ereignisse: 50, total_added: 5000 }.
    • Senden Sie eine Nachricht.
  3. Snapshot-Stream: Alle 1 Minute. Vollständige Synchronisierung. Bringen Sie „Echtzeitgefühl“ mit „menschlichen kognitiven Grenzen“ in Einklang.

13. Die „Builder vs. Buy“-Entscheidung (Grafana)

Manchmal müssen Sie kein benutzerdefiniertes React-Dashboard erstellen. Wenn die Zielgruppe „Ingenieure“ oder „Internal Ops“ ist, verwenden Sie einfach Grafana. Verbinden Sie es mit Ihrem PostgreSQL-Lesereplikat. Stellen Sie die Bildwiederholfrequenz auf 5 Sekunden ein. Erledigt. Kostet 0 €. Wir erstellen benutzerdefinierte React-Dashboards nur, wenn es sich bei der Zielgruppe um „externe Kunden“ oder „C-Level-Führungskräfte, die eine bestimmte UX benötigen“ handelt.

14. Warnschwellen (visuelle Hinweise)

Eine Zahl, die sich von 100 auf 120 ändert, sind Daten. Eine Zahl, die von 100 auf 120 (roter Hintergrund) wechselt, ist eine Information. Wir bauen „Threshold Logic“ in die Frontend-Komponenten ein. if (value < target) color = 'red'. Dies hilft Benutzern, den Echtzeit-Stream kognitiv zu verarbeiten. „Ich muss die Zahlen nicht lesen; ich muss nur nach Rot suchen.“

15. Fazit

Beim Aufbau eines Echtzeit-Dashboards geht es darum, die Illusion der Unmittelbarkeit in den Griff zu bekommen. Es erfordert einen synchronisierten Tanz zwischen der Datenbank, dem Ereignisbus, dem Webserver und der Client-Benutzeroberfläche. Schlecht durchgeführt, führt dies zu einem Leistungsengpass. Wenn es gut gemacht ist, fungiert es als Herzschlag der Organisation.


Sind Ihre Daten veraltet?

Wir bauen Hochfrequenz-Handelsschnittstellen für den Einzelhandel.

Stellen Sie unsere Echtzeitarchitekten ein. Beauftragen Sie unsere Architekten.