分布式 WebSocket 集群解决方案

下面我将描述session特性,以及根据这些特性列举出n个解决分布式架构中处理ws请求的集群方案

WebSocketSession与HttpSession

在Spring所集成的WebSocket里面,每个ws连接都有一个对应的session:WebSocketSession,在Spring WebSocket中,我们建立ws连接之后可以通过类似这样的方式进行与客户端的通信:

protected void handleTextMessage(WebSocketSession session, TextMessage message) {

System.out.println("服务器接收到的消息: "+ message );

//send message to client

session.sendMessage(new TextMessage(“message”));

}

那么问题来了:ws的session无法序列化到redis,因此在集群中,我们无法将所有WebSocketSession都缓存到redis进行session共享。每台服务器都有各自的session。于此相反的是HttpSession,redis可以支持httpsession共享,但是目前没有websocket session共享的方案,因此走redis websocket session共享这条路是行不通的。

有的人可能会想:我可不可以将sessin关键信息缓存到redis,集群中的服务器从redis拿取session关键信息然后重新构建websocket session…我只想说这种方法如果有人能试出来,请告诉我一声…

以上便是websocket session与http session共享的区别,总的来说就是http session共享已经有解决方案了,而且很简单,只要引入相关依赖:spring-session-data-redisspring-boot-starter-redis,大家可以从网上找个demo玩一下就知道怎么做了。而websocket session共享的方案由于websocket底层实现的方式,我们无法做到真正的websocket session共享。

解决方案的演变

Netty与Spring WebSocket

刚开始的时候,我尝试着用netty实现了websocket服务端的搭建。在netty里面,并没有websocket session这样的概念,与其类似的是channel,每一个客户端连接都代表一个channel。前端的ws请求通过netty监听的端口,走websocket协议进行ws握手连接之后,通过一些列的handler(责链模式)进行消息处理。与websocket session类似地,服务端在连接建立后有一个channel,我们可以通过channel进行与客户端的通信

如果您正在学习Spring Boot,推荐一个连载多年还在继续更新的免费教程:http://blog.didispace.com/spring-boot-learning-2x/

/**

* TODO 根据服务器传进来的id,分配到不同的group

*/

private static final ChannelGroup GROUP = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);

@Override

protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {

//retain增加引用计数,防止接下来的调用引用失效

System.out.println("服务器接收到来自 " + ctx.channel().id() + " 的消息: " + msg.text());

//将消息发送给group里面的所有channel,也就是发送消息给客户端

GROUP.writeAndFlush(msg.retain());

}

那么,服务端用netty还是用spring websocket?以下我将从几个方面列举这两种实现方式的优缺点

使用netty实现websocket

玩过netty的人都知道netty是的线程模型是nio模型,并发量非常高,spring5之前的网络线程模型是servlet实现的,而servlet不是nio模型,所以在spring5之后,spring的底层网络实现采用了netty。如果我们单独使用netty来开发websocket服务端,速度快是绝对的,但是可能会遇到下列问题:

  1. 与系统的其他应用集成不方便,在rpc调用的时候,无法享受springcloud里feign服务调用的便利性

  2. 业务逻辑可能要重复实现

  3. 使用netty可能需要重复造轮子

  4. 怎么连接上服务注册中心,也是一件麻烦的事情

  5. restful服务与ws服务需要分开实现,如果在netty上实现restful服务,有多麻烦可想而知࿰

你可能感兴趣的:(程序员,分布式,websocket,网络协议)