keepcalculator

06 Numbers and Powers

Java WebSocket Backend: Key Facts for Choosing & Deploying

Card No. 06·6325 · Updated · Standard formula, shown below

Java WebSocket support is built into the platform since Java EE 7 (JSR 356), so you can add real-time, two-way messaging to a backend without external libraries. The key facts for choosing and deploying are: use the standard javax.websocket (or jakarta.websocket) API for portability, pick an implementation that fits your runtime (Tomcat, Jetty, Undertow, or a full app server), and plan for load balancing with sticky sessions or a separate message broker. This article covers the API basics, how to choose an implementation, common deployment pitfalls, and performance considerations.

Background: How WebSocket Works in Java

WebSocket is a full-duplex protocol over a single TCP connection, defined by RFC 6455. The client sends an HTTP upgrade request, and if the server agrees, the connection switches from HTTP to WebSocket frames. In Java, the JSR 356 specification standardizes this with annotations and programmatic endpoints.

  • @ServerEndpoint – marks a class as a WebSocket endpoint; you can specify the URI path, e.g., @ServerEndpoint("/chat").
  • @OnOpen, @OnMessage, @OnClose, @OnError – callback methods for lifecycle events.
  • Session – represents the connection; you can send messages and store user properties.
  • Encoder/Decoder – convert between Java objects and WebSocket messages (text or binary).

The API is part of Jakarta EE (formerly Java EE). If you use Spring Boot, you can also use Spring’s WebSocket support, which wraps the standard API but adds STOMP messaging and easier integration with Spring Security.

How to Choose an Implementation

Your choice of WebSocket implementation depends on your application server or embedded runtime. Each has its own configuration and performance characteristics.

  • Tomcat – Supports WebSocket since 7.0.47. In Tomcat 9 and 10, the implementation is mature. Use the javax.websocket (Tomcat 9) or jakarta.websocket (Tomcat 10+) API. Configuration is via @ServerEndpoint or programmatic registration.
  • Jetty – Known for high concurrency. Jetty 9+ supports JSR 356. Often used in embedded mode; you can add WebSocket support with a few lines of code.
  • Undertow – The default in WildFly; also works standalone. It’s lightweight and supports both the standard API and its native API.
  • Spring Boot – When you include spring-boot-starter-websocket, it uses the underlying server’s implementation (Tomcat, Jetty, or Undertow) and adds Spring’s abstraction. You can use @MessageMapping with STOMP for a higher-level messaging pattern.

For new projects, if you are already using Spring Boot, stick with Spring’s WebSocket support. If you are writing plain Java EE, use the standard API with a compatible server. Avoid mixing implementations unless you have a specific reason.

Deployment Considerations

Deploying a WebSocket backend is different from a standard HTTP service because connections are long-lived and stateful.

Load Balancing and Sticky Sessions

WebSocket connections are tied to a specific server instance. If you have multiple backend nodes, a load balancer must route all messages from a client to the same node for the duration of the connection. This is called sticky sessions (or session affinity). Most load balancers support this via a cookie or source IP. Without sticky sessions, a client might connect to one node, then a subsequent request goes to another node, breaking the connection.

Scaling with a Message Broker

If you need to broadcast messages across multiple nodes, you need a shared messaging layer. Options include:

  • Redis Pub/Sub – Simple and popular; use it to forward messages between nodes.
  • RabbitMQ or Apache Kafka – More robust, with persistence and delivery guarantees.
  • STOMP broker (e.g., ActiveMQ) – If you use Spring’s STOMP support, you can connect to a full broker or use a simple in-memory broker for single-node.

Without a broker, you can only broadcast within a single JVM. For a small app, that’s fine; for production with multiple instances, you need a broker.

Connection Limits and Timeouts

Each WebSocket connection consumes a thread (or at least a file descriptor) and memory. Set appropriate limits in your server configuration:

  • Tomcat – maxConnections and maxThreads in the connector.
  • Jetty – maxConnections and idleTimeout.
  • Undertow – max-connections in the undertow subsystem.

Also set a reasonable idleTimeout on the session to close connections that have been silent for too long. The default is often 60 seconds in some servers, but for chat apps you might want longer.

Common Problems and Pitfalls

Here are frequent issues developers encounter:

  • Proxy buffering – Some reverse proxies (like nginx) buffer HTTP responses by default. For WebSocket, you must set Upgrade and Connection headers correctly and disable buffering. In nginx, you need proxy_set_header Upgrade $http_upgrade; and proxy_set_header Connection "upgrade";.
  • Sticky session misconfiguration – If your load balancer doesn’t use sticky sessions, clients will disconnect randomly.
  • Using HTTP session for WebSocket – WebSocket sessions are not HTTP sessions. If you need to associate a user, store the user ID in the WebSocket session’s user properties during the handshake (e.g., from a cookie or token).
  • Not handling concurrent sends – The Session.getBasicRemote().sendText() is not thread-safe; use getAsyncRemote() or synchronize on the session.
  • Memory leaks – Always remove sessions from your registry on @OnClose. Otherwise, you’ll leak memory as connections close.

Performance and Scalability

WebSocket is efficient because it avoids HTTP overhead after the handshake. However, the Java implementation still uses threads per connection in many servers. For very high concurrency (tens of thousands), consider:

  • Non-blocking I/O – Jetty and Undertow use NIO, which can handle more connections with fewer threads than Tomcat’s BIO (though Tomcat 9+ also uses NIO).
  • Asynchronous send – Use getAsyncRemote() to avoid blocking a thread.
  • Message size – Set a reasonable max message size to prevent memory exhaustion. In Tomcat, maxTextMessageSize default is 8192 bytes.

For most applications, a single node with a few thousand concurrent connections is fine. If you need more, you must scale out with a broker.

Security Considerations

WebSocket connections are subject to the same security concerns as HTTP, plus a few extras:

  • Origin checking – Validate the Origin header during the handshake to prevent cross-site WebSocket hijacking.
  • Authentication – Authenticate during the HTTP upgrade (e.g., with cookies or a token in the query string). Do not rely on the WebSocket protocol itself for auth.
  • Encryption – Use wss:// (TLS) in production to protect data in transit.
  • Input validation – Treat all messages as untrusted; validate and sanitize them just like HTTP input.

Also, be aware that WebSocket connections bypass normal HTTP caching and some security filters. Ensure your security middleware is applied during the handshake.

Alternatives to WebSocket

WebSocket is not always the best choice. Consider these alternatives:

  • Server-Sent Events (SSE) – One-way server-to-client push over HTTP. Simpler, works with standard HTTP load balancers, and automatically reconnects. Use if you only need server-to-client updates.
  • Long polling – Client repeatedly requests; server holds the response until an update. Works everywhere but has more overhead.
  • HTTP/2 Server Push – Not for real-time bidirectional, but can push resources.

If you need full-duplex, low-latency communication, WebSocket is the standard. If you only need notifications, SSE is often simpler.

Frequently Asked Questions

What is the difference between javax.websocket and jakarta.websocket?

They are the same API. The package name changed from javax.websocket to jakarta.websocket when Oracle transferred Java EE to the Eclipse Foundation. Use jakarta.websocket with Jakarta EE 9+ and Tomcat 10+. If you are on Java EE 8 or Tomcat 9, use javax.websocket.

Can I use WebSocket with Spring Boot?

Yes. Spring Boot supports WebSocket via the spring-boot-starter-websocket starter. You can use the raw WebSocket API or Spring’s STOMP messaging. Spring Boot automatically configures the WebSocket handler based on the embedded server.

How do I broadcast a message to all connected clients?

You need to keep a registry of all sessions. On @OnOpen, add the session to a concurrent set; on @OnClose, remove it. To broadcast, iterate over the set and send to each session. For multi-node, use a message broker to forward messages.

Why does my WebSocket connection drop after 60 seconds?

Many servers have an idle timeout. For example, Tomcat’s default is 60 seconds for WebSocket sessions. Set session.setMaxIdleTimeout(0) to disable, or set a longer value. Also check your load balancer or proxy for idle timeouts.

Is WebSocket supported on all Java application servers?

Most modern ones do: Tomcat 7.0.47+, Jetty 9+, WildFly, GlassFish 4+, and WebLogic 12.1.2+. Older servers may not. If you are unsure, check the server documentation for JSR 356 support.

Can I use WebSocket with a serverless platform?

Generally no, because WebSocket requires a persistent connection. Serverless functions are short-lived. Some platforms offer WebSocket API Gateway (like AWS API Gateway) that proxies to Lambda, but the connection is managed by the gateway, not your Java code.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →