PDA-LOG-008
ARCHITECTURE

Socket.IO & WebSockets: Real-Time Systeme für Production

Echtzeit-Kommunikation ist kein Nice-to-have mehr — sie ist Kerninfrastruktur. Socket.IO und WebSockets richtig zu architektonieren bedeutet: skalierbar, ausfallsicher und messbar.

Publiziert01.04.2026
Lesezeit07:00 MIN
AutorPalmer Digital

Die Erwartung an moderne Web-Applikationen hat sich fundamental verschoben. Nutzer erwarten Live-Updates, Kollaboration in Echtzeit und sofortige System-Reaktionen — nicht nach einem Browser-Refresh, sondern unmittelbar. Socket.IO ist die produktionserprobte Antwort auf diese Anforderung: eine Abstraktion über WebSockets mit automatischem Fallback, strukturiertem Event-System und horizontaler Skalierbarkeit.

WebSocket vs. HTTP: Der fundamentale Unterschied

HTTP ist ein Request-Response-Protokoll — der Client fragt, der Server antwortet, die Verbindung wird geschlossen. Für statische Inhalte ist das optimal. Für Echtzeit-Daten ist es ein Architektur-Antipattern. WebSockets etablieren eine persistente, bidirektionale Verbindung. Einmal geöffnet, können Server und Client jederzeit Nachrichten senden — ohne den Overhead eines neuen HTTP-Handshakes.

Socket.IO Server-Setup mit Express und Namespace-Architektur
import { createServer } from "http";
import { Server } from "socket.io";
import express from "express";

const app = express();
const httpServer = createServer(app);

const io = new Server(httpServer, {
    cors: { origin: process.env.CLIENT_URL, credentials: true },
    transports: ["websocket", "polling"], // WebSocket first, polling als Fallback
});

// Namespace: isolierter Kommunikationskanal pro Feature-Bereich
const dashboardNS = io.of("/dashboard");

dashboardNS.on("connection", (socket) => {
    console.log(`Client connected: ${socket.id}`);

    // Room: Nutzer-spezifische Gruppe innerhalb des Namespace
    socket.on("join:project", (projectId: string) => {
        socket.join(`project:${projectId}`);
        socket.emit("joined", { projectId, timestamp: Date.now() });
    });

    // Broadcast an alle im Room — exkl. Sender
    socket.on("data:update", (payload) => {
        socket.to(`project:${payload.projectId}`).emit("data:changed", payload);
    });

    socket.on("disconnect", (reason) => {
        console.log(`Client disconnected: ${reason}`);
    });
});

httpServer.listen(3001);

Horizontale Skalierung mit Redis Adapter

Ein einzelner Socket.IO Server ist limitiert auf die Verbindungen, die ein Node.js-Prozess verwalten kann. Sobald mehrere Server-Instanzen betrieben werden — sei es für Hochverfügbarkeit oder Last-Verteilung — entsteht das Problem: Client A ist mit Server 1 verbunden, Client B mit Server 2. Ein Event von Client A erreicht Client B nicht ohne gemeinsamen Message-Bus. Die Lösung: der Redis Adapter.

Redis Adapter für Multi-Instance Socket.IO Deployment
import { createAdapter } from "@socket.io/redis-adapter";
import { createClient } from "redis";

const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();

await Promise.all([pubClient.connect(), subClient.connect()]);

// Alle Server-Instanzen teilen denselben Redis-Pub/Sub-Channel
io.adapter(createAdapter(pubClient, subClient));

// Ab jetzt: io.to(room).emit() funktioniert über alle Instanzen hinweg
// Server 1 kann Clients auf Server 2 erreichen — transparent
INFO

Der Redis Adapter ist die produktionserprobte Standardlösung für horizontale Socket.IO-Skalierung. Für Deployments auf Railway oder Vercel Edge Functions empfiehlt sich zusätzlich eine Sticky-Session-Konfiguration am Load Balancer, um den WebSocket-Upgrade-Handshake zu stabilisieren.

Reconnection & State Recovery

Netzwerkunterbrechungen sind unvermeidlich. Eine robuste Echtzeit-Architektur behandelt Reconnection nicht als Ausnahme, sondern als regulären Betriebszustand. Socket.IO bietet eingebaute Reconnection-Logik — entscheidend ist jedoch, was nach dem Wiederverbinden passiert: Welcher State wurde verpasst? Welche Events müssen nachgeliefert werden?

  • Socket.IO reconnectionAttempts und reconnectionDelay konfigurieren — kein blindes Reconnect-Flooding
  • Server-seitig: offlineQueue pattern — Events während Disconnect im Redis buffern und bei Reconnect flushen
  • Client-seitig: lastEventId mitsenden — Server liefert alle Events seit letztem bekannten Stand nach
  • Für kritische Systeme: Acknowledgements (ACK) als Delivery-Garantie nutzen, nicht Fire-and-Forget
TIP

Socket.IO ist nicht das richtige Werkzeug für jeden Echtzeit-Use-Case. Für rein server-to-client Push-Notifications (ohne Client→Server-Events) sind Server-Sent Events (SSE) oft die einfachere und ressourcenschonendere Alternative — insbesondere auf Vercel Edge Functions mit ihrem connectionless Deployment-Modell.