Files
2nd/10_Wiki/Topics/Backend/WebSockets_and_Realtime.md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

5.6 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-websockets-and-realtime WebSockets and Realtime 10_Wiki/Topics verified self
WebSockets
Realtime Communication
WS
none A 0.9 applied
websockets
realtime
low-latency
pubsub
full-duplex
2026-05-10 pending
language framework
TypeScript / Go Bun / uWebSockets.js / Centrifugo

WebSockets and Realtime

매 한 줄

"매 single TCP connection over HTTP upgrade — 매 full-duplex, low-overhead binary/text framing 의 realtime 표준". 2011 RFC 6455, 2026 WebTransport (HTTP/3) 가 등장했지만 WS 는 여전히 ubiquitous. 매 chat, collaborative editing, live dashboards, gaming 의 backbone.

매 핵심

매 Lifecycle

  1. HTTP GET + Upgrade: websocket + Sec-WebSocket-Key.
  2. Server 의 101 Switching Protocols + Sec-WebSocket-Accept.
  3. Frame-based (text=0x1, binary=0x2, ping=0x9, pong=0xA, close=0x8).
  4. Full-duplex 까지 매 connection 의 close.

매 Scaling challenges

  • Sticky session 또는 pub/sub fanout: 매 connection 의 single node binding.
  • Backpressure: slow client → memory bloat. bufferedAmount watch.
  • Reconnect + resume: client state 의 server-side snapshot.
  • Auth: query token (logged in proxies) vs. first-message handshake (recommended).

매 대안 매트릭스

  • SSE: server → client only, simpler, HTTP/2 multiplexed.
  • WebTransport: HTTP/3, datagrams + streams, 매 future.
  • Long polling: legacy fallback.

매 응용

  1. Chat / collaborative docs (Yjs, Liveblocks).
  2. Trading / live odds / dashboards.
  3. Multiplayer game (low-tick) — 매 보통 UDP/WebTransport 가 더 좋음.
  4. AI streaming (token-by-token, 매 SSE 가 더 흔함).

💻 패턴

Bun WebSocket server (high perf)

Bun.serve<{ userId: string }>({
  port: 3000,
  fetch(req, server) {
    const userId = verifyJWT(new URL(req.url).searchParams.get('token'));
    if (!userId) return new Response('unauth', { status: 401 });
    if (server.upgrade(req, { data: { userId } })) return;
    return new Response('expected ws', { status: 400 });
  },
  websocket: {
    open(ws) { ws.subscribe(`user:${ws.data.userId}`); },
    message(ws, msg) {
      const { room, body } = JSON.parse(msg as string);
      ws.publish(`room:${room}`, JSON.stringify({ from: ws.data.userId, body }));
    },
    close(ws) { /* cleanup */ },
  },
});

Client with auto-reconnect

class RealtimeClient {
  private ws?: WebSocket;
  private retry = 0;

  connect() {
    this.ws = new WebSocket(`wss://api/rt?token=${this.token}`);
    this.ws.onopen = () => { this.retry = 0; this.flush(); };
    this.ws.onmessage = (e) => this.dispatch(JSON.parse(e.data));
    this.ws.onclose = () => {
      const delay = Math.min(30_000, 2 ** this.retry++ * 1000) + Math.random() * 500;
      setTimeout(() => this.connect(), delay);
    };
  }
  send(obj: unknown) {
    if (this.ws?.readyState === 1) this.ws.send(JSON.stringify(obj));
    else this.queue.push(obj);
  }
}

Redis pub/sub fanout (multi-node)

const sub = redis.duplicate();
await sub.subscribe('room:*', (msg, channel) => {
  const room = channel.split(':')[1];
  server.publish(`room:${room}`, msg);  // 매 local connections 만
});

// publisher (any node)
await redis.publish(`room:${room}`, JSON.stringify(payload));

Heartbeat + dead connection detection

setInterval(() => {
  for (const ws of server.publishToSubscribers) {
    if (Date.now() - ws.data.lastPong > 60_000) ws.close(1011, 'stale');
    else ws.ping();
  }
}, 30_000);

Yjs collaborative doc

import * as Y from 'yjs';
import { WebsocketProvider } from 'y-websocket';

const doc = new Y.Doc();
const provider = new WebsocketProvider('wss://yjs.example/sync', `doc:${docId}`, doc);
const text = doc.getText('content');
text.observe(e => render(text.toString()));
text.insert(0, 'Hello');  // 매 CRDT-merged 매 모든 client

Backpressure

ws.send(payload);
if (ws.bufferedAmount > 1_000_000) {
  ws.close(1013, 'backpressure');  // drop slow client
}

매 결정 기준

상황 Approach
Server → client only stream SSE (simpler, HTTP/2)
Bidirectional, < 10k conn / node WebSocket on Bun/Node
100k+ conn / node uWebSockets.js, Go (gobwas/ws), Rust
Managed pub/sub Centrifugo, Ably, Pusher
Collab editing Yjs / Automerge over WS
Low-latency game WebTransport (HTTP/3)

기본값: WSS + JWT in first message + Redis pub/sub fanout + 30s heartbeat + exponential reconnect.

🔗 Graph

🤖 LLM 활용

언제: server scaffolding, reconnect logic, fanout pattern. 언제 X: 매 production-scale tuning (kernel, ulimit, TLS termination) — empirical.

안티패턴

  • No heartbeat: 매 NAT/proxy 의 silent close → zombie connections.
  • Token in URL query: 매 server log 의 leak. Use first-message handshake.
  • Synchronous DB call in onmessage: blocks event loop.
  • Per-connection in-memory state w/o backup: 매 node restart → data loss.
  • No backpressure check: slow client OOMs server.

🧪 검증 / 중복

  • Verified (RFC 6455, Bun/uWS docs, Yjs/Centrifugo prod patterns).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — Bun WS + reconnect + Redis fanout 패턴