WebSockets vs Long Polling: Choosing a Real-Time Transport
Your client needs live updates. New messages, price changes, status notifications. HTTP is request-response. Client asks, server answers. Server can’t just push data whenever it wants.
So we hack around it. And the hack you choose matters more than you’d think.
Long Polling#
Client sends a request. Server holds it open until there’s new data or a timeout hits. Client gets the response, immediately sends another request. Repeat forever.
@GetMapping("/updates")
public DeferredResult<List<Event>> poll(@RequestParam long lastEventId) {
DeferredResult<List<Event>> result = new DeferredResult<>(30000L);
eventBroker.subscribe(lastEventId, result::setResult);
result.onTimeout(() -> result.setResult(Collections.emptyList()));
return result;
}
Simple. Works through proxies and firewalls. But every “connection” is a full HTTP request with headers. At scale, that overhead adds up fast.
Server-Sent Events#
One-way stream from server to client. Single HTTP connection stays open, server pushes events down. Built into browsers natively. Great for dashboards, live feeds, anything where the client just listens. But it’s one-directional only.
WebSockets#
Full-duplex. Single TCP connection, both sides send freely. Starts as HTTP, then upgrades to the WebSocket protocol.
@ServerEndpoint("/ws")
public class LiveEndpoint {
@OnMessage
public void onMessage(Session session, String message) {
session.getOpenSessions().forEach(s ->
s.getAsyncRemote().sendText(message)
);
}
}
Lowest overhead per message. But persistent connections mean you need sticky sessions on your load balancer, your graceful shutdown gets harder (draining live connections), and your connection pool math changes completely.
When to Use What#
At Oracle, we started with long polling for our NSSF notification service. Worked fine at low scale. Once we hit thousands of connected clients, the constant HTTP reconnections were eating CPU. Switching to WebSockets cut our connection-related overhead by roughly 50%.
SSE is the underrated middle ground. If your use case is “server pushes updates to client” (alerts, dashboards, log tailing), SSE gives you most of WebSocket’s benefits with way less operational complexity.
What I’m Learning#
The transport choice cascades into every infrastructure decision: load balancer config, deploy strategy, connection limits, monitoring. WebSockets aren’t always better. They’re just different, and the trade-offs only show up at scale.
Start with long polling or SSE. Move to WebSockets when you actually need bidirectional communication.
What real-time transport are you using? Have you hit the scaling wall with long polling?