Implementing Distributed WebSocket Clusters with Spring Cloud, Consistent Hashing, and Gateway
This article explores practical approaches for building a distributed WebSocket cluster in a Spring Cloud environment, covering session handling, Netty versus Spring WebSocket implementations, session broadcasting, consistent‑hash routing, gateway configuration, Ribbon limitations, and provides code examples for each solution.
The author describes a real‑world scenario where multiple users need to communicate via WebSocket in a clustered environment, involving four servers (one with SSL, a Redis+MySQL server, and two application servers) and strict SSL gateway requirements.
Technology stack: Eureka, Redis (session sharing and pub/sub), Spring Boot, Zuul, Spring Cloud Gateway, Spring WebSocket, Ribbon, Netty, and Consistent Hash algorithm.
WebSocketSession vs HttpSession: WebSocket sessions cannot be serialized to Redis, making true session sharing impossible, whereas HttpSession sharing is straightforward with spring-session-data-redis and spring-boot-starter-redis .
Solution evolution:
Netty implementation
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
System.out.println("服务器接收到的消息: " + message);
// send message to client
session.sendMessage(new TextMessage("message"));
}Netty offers high concurrency but introduces integration challenges, duplicate business logic, and difficulty with service discovery and load balancing.
Spring WebSocket implementation
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency> @Configuration
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/").setAllowedOrigins("*");
}
@Bean
public WebSocketHandler myHandler() {
return new MessageHandler();
}
} @Component
public class MessageHandler extends TextWebSocketHandler {
private List
clients = new ArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
clients.add(session);
System.out.println("uri :" + session.getUri());
}
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
String payload = message.getPayload();
clients.forEach(s -> {
try { s.sendMessage(new TextMessage("服务器返回收到的信息," + payload)); }
catch (Exception e) { e.printStackTrace(); }
});
}
}The Spring WebSocket approach integrates easily with Spring Cloud, allowing a single service to handle both RESTful and WebSocket traffic.
Session broadcasting: A simple method where the gateway forwards a teacher's broadcast to all cluster nodes, each checking for relevant sessions. This is easy but wastes CPU when no matching sessions exist.
Consistent hashing solution (core focus): Uses a hash ring to map user IDs to specific cluster nodes, handling node up/down events via Eureka listeners and Redis‑based ring sharing. Virtual nodes improve distribution stability.
Node‑down handling removes the node and its virtual nodes from the ring; node‑up handling updates the ring and may force client reconnections to rebalance sessions.
Gateway configuration for SSL and WS forwarding:
server:
port: 443
ssl:
enabled: true
key-store: classpath:xxx.jks
key-store-password: xxxx
key-store-type: JKS
key-alias: alias
spring:
application:
name: api-gateway
cloud:
gateway:
httpclient:
ssl:
handshake-timeout-millis: 10000
discovery:
locator:
enabled: true
routes:
- id: dc
uri: lb://dc
predicates:
- Path=/dc/**
- id: wecheck
uri: lb://wecheck
predicates:
- Path=/wecheck/**A custom HttpsToHttpFilter converts HTTPS requests to HTTP for proper routing.
Ribbon limitations in Finchley: Custom load‑balancing rules interfere with multi‑service routing, and the lack of a key parameter prevents direct consistent‑hash routing, leading to a two‑step client approach (HTTP to obtain target IP, then WS connection).
In conclusion, the article presents two viable distributed WebSocket strategies—session broadcast and consistent hashing—each suited to different traffic patterns, and provides practical code snippets and configuration guidance for implementation.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.