top of page

WebSockets

  • Writer: Pradeep P
    Pradeep P
  • 3 days ago
  • 3 min read

Layer 2 · Post 8 of 10

Layer 2 — Communication · Post 23 of 88

WebSockets keep a two-way connection open so the server can push updates instantly instead of waiting for the client to ask again.

What you'll learn

  • Why polling hurts, and what a WebSocket actually is

  • How to scale a fleet of socket servers (sticky connections, pub/sub fan-out)

  • When WebSockets are overkill

The idea in one minute

HTTP is request/response. The server cannot talk until the client asks.

WebSocket starts as HTTP (Upgrade: websocket) and becomes a long-lived, bidirectional TCP connection. Either side can send frames whenever.

That is how chat, live cursors, multiplayer, and "the dashboard just updated" feel instant.

Why it matters

Polling every 2 seconds from 100,000 tabs is 50,000 empty requests per second. Load balancers and origin hate you. Latency is up to 2 seconds.

A socket per tab is not free either (memory, file descriptors, idle timeouts), but for true realtime it is the standard browser tool.

How it works

  1. Client connects to wss://api.example.com/ws (TLS).

  2. Handshake: HTTP 101 Switching Protocols.

  3. Messages: text or binary frames. You define the JSON protocol (type: "message", roomId, ...).

  4. Heartbeats/ping so load balancers do not kill idle connections.

  5. Reconnect with backoff when the phone goes through a tunnel.

Scaling beyond one box

A connection is stuck to one server. User A on server 1, user B on server 2, A messages B:

  • Server 1 must publish the message to Redis/NATS/Kafka.

  • Server 2 subscribes and writes to B's socket.

Without that bus, you have a chat app that only works when both users hit the same pod.

Sticky load balancing (cookie or IP) keeps reconnects on the same node when you can. It is not a substitute for the bus.

Auth

Pass a token on the handshake (query string is ugly but common; first-message auth is cleaner). Authorize per subscription (join room X) so a stolen socket cannot listen to everything.

A simple example

Support chat:

  • Browser opens wss://.

  • Sends { "type": "join", "ticketId": "99" }.

  • Agent types; server publishes to ticket:99; all sockets in that room receive { "type": "msg", "text": "..." }.

  • History still lives in a DB. The socket is the live tail, not the system of record.

Common mistakes

No reconnect / no resume. Mobile networks drop. Clients must reconnect and fetch missed messages by seq or timestamp.

Business logic only in memory on the socket box. Deploy = amnesia. Persist.

One process, all users. You will need the fan-out bus sooner than you think.

Using WebSockets for occasional updates. SSE (next post) or short polling may be simpler. WebSockets for a daily notification is a lot of connection state.

How this shows up in real systems

  • Slack, Discord, Figma, trading UIs: sockets or socket-like (sometimes QUIC / custom).

  • Socket.IO, ws, SignalR: application libraries on top.

  • API Gateway WebSocket APIs, Cloudflare Durable Objects: managed connection routing.

Layer 6 "design a chat system" is this post plus fan-out, presence, and storage.

Recap

  • WebSockets are persistent, two-way connections after an HTTP upgrade.

  • Scale with a pub/sub bus between socket servers, not hope.

  • Keep the DB as truth; the socket is the live pipe.

If you only need server → browser updates, SSE is a thinner tool.

Layer 2 · Post 8 of 10

Comments


About Me

DSC_7604.jpg

Hi, I am a software engineer from Bangalore, India. Love spending time on gaming and photography. This website is where I will ocassionally throw what comes to my mind. Hope it is useful or at least entertaining to you. :)

 

  • Instagram
  • Facebook
  • Twitter
  • LinkedIn
  • YouTube
  • 500px

© 2023 by Going Places. Proudly created with Wix.com

bottom of page