最近,在进行项目时,它遇到了需要在多个用户之间传达的问题,涉及握手请求的问题以及在集群中共享Websocket会话的问题。
经过几天的研究,我总结了几种实现分布式Websocket群集的方法。从Zuul到Spring Cloud Gateway的不同尝试,我总结了这篇文章,希望能帮助某些人,并能够成为该领域的思想和研究。
以下是我的场景描述
在我的实施中,每个应用程序服务器负责HTTP和WS请求。实际上,您还可以分别设置WS请求建立的聊天模型。从分布式的角度来看,这两种类型的实现相似,但是从实施的便利性,应用程序服务http+ws请求是更多方便。下面有一个解释
本文涉及的技术堆栈
我相信可以达到这一步骤的人了解了我上面列出的技术堆栈。如果没有,您可以首先在线查找条目教程。以下内容与上述技术有关。每个人都知道主题的默认值...
下面我将描述会话特征,并列出基于这些特征在分布式体系结构中处理WS请求的群集方案
WebSocketsession和Httpsession
在Spring集成的Websocket中,每个WS连接都有一个相应的会话:WebSocketsession。在Spring Websocket中,我们可以在建立WS连接后与客户端进行通信:我们可以建立WS连接:客户端:
然后问题是:WS会话不能序列化与REDIS序列化,因此在群集中,我们不能缓存所有的WebSocketSession以共享会话的会话。EADS服务器具有自己的会话。相反的是Httpsession。REDIS可以支持HTTPSESSION共享,但是没有解决Websocket会话共享的解决方案。因此,这是不可能的
有些人可能会想:我可以缓存Sessin到Redis的关键信息吗尝试,如果有人可以尝试一下,如果有人可以尝试一下,如果有人可以尝试一下,如果有人可以尝试一下,如果有人可以尝试一下,可以尝试。请告诉我...
以上是Websocket会话和HTTP会话之间的区别。通常,HTTP会话共享具有解决方案,这很简单。它的正确性。由于网站的基本实现,Websocket会话共享的解决方案,我们无法实现真正的WebSocket会话共享。
Netty和Spring Websocket
一开始,我试图用Netty来实现Websocket服务器的构建。它类似于通道。每个客户端连接代表一个频道。正面 - 端WS请求通过netty通过websocks协议,通过NETTY连接到WebSocket协议,并通过某些列处理程序(负责任的链模式)进行消息处理。类似于WebSocket,服务器具有频道建立连接后。我们可以通过渠道与客户沟通
那么,服务器是否使用Netty或Spring Websocket?下方我将从几个方面列出这两个实现的优点和缺点
任何使用Netty实施Websocket的人都知道Netty的线程模型是NIO模型,并且并发量很高。Spring5的先前网络线程模型由Servlet实现,该服务不是NIO模型。因此,在Spring5之后,春季5的底部网络实现使用Netty。如果我们仅使用Netty来开发WebSocket服务器,则速度是绝对快的,但是我们可能会遇到以下问题:
Springboot的使用Spring Websocket实施了Spring Websocket已很好地集成了Spring Websocket,因此在Springboot上开发WS服务非常方便,并且实践非常简单。
春季靴将不会引入基础。推荐本实际教程:https://github.com/javastacks/spring-boot-best-practice
步骤1:添加依赖项
步骤2:添加配置类
步骤3:实施消息监视类别
从这个演示中,每个人都可以想象使用Spring Websocket的WS服务的便利性。为了更好地查看Spring Cloud家族,我终于使用Spring Websocket实施了WS服务。
因此,我的应用程序服务体系结构是这样的:应用程序负责RESTFUL服务和WS服务。WS服务模块没有拆分,因为它被拆分以将其用于服务呼叫。第一人称更懒惰。第二拆分和非拆卸部门之间的区别是服务层之间的IO调用,因此我没有这样做。
为了实现Websocket群集,我们必须从Zuul转换为Spring Cloud Gateway。原因如下:
Zuul 1.0版本不支持WebSocket转发。Zuul 2.0开始支持Websocket。Zuul2.0几个月前是开源的,但是版本2.0并未由Spring Boot集成,并且文档未完成。因此,需要进行转换,并且转换也很容易实现。
在网关中,为了实现SSL身份验证和动态路由负载平衡,需要在YML文件下方的某些配置,在这里您可以提前避免使用坑。
春季靴将不会引入基础。推荐本实际教程:https://github.com/javastacks/spring-boot-best-practice
如果您想快乐地玩HTTP
这样,我们可以使用网关卸载HTTPS请求。到目前为止,我们的基本框架已经建立。网关可以转发HTTPS请求或WSS请求。下一步是用户之间的互操作性的通信解决方案。Next,我将从计划的优雅开始,并从最优雅的解决方案开始。
这是最简单的Websocket集群通信解决方案。场景如下:
老师A想向他的学生发送消息
会话广播的实现非常简单,但是存在致命的缺陷:计算功率浪费,当服务器没有消息接收器会话时,它等同于浪费循环的计算能力。实施。
弹簧云中服务群集中每个服务器信息的方法如下
服务器需要维护关系的映射表,并邮寄用户的ID和会话。建立会话后,在映射表中添加映射关系。会话断开连接后
这种方法是认为最优雅的实施计划,了解该计划需要一定时间。如果您耐心地看着它,我相信您会获得一些重点。另一个重点,不了解一致性哈希算法的学生,请先查看它,现在假设哈希环是顺时针旋转的。
首先,如果您想将一致的哈希算法的想法应用于我们的Websocket群集,我们需要解决以下新问题:
在集群中,服务UP/DON总会出现问题。
对节点下降的问题的分析如下:
当服务器关闭时,WebSocket会话将自动关闭连接并将通知前端。这次,它将影响Hash Ring的映射错误。当我们只需要听到服务器下降时,我们只会删除哈希环上的实际节点和虚拟节点,以避免让门户向前驶向状态下降的服务器。
实施方法:尤里卡治理中心的Donn Service,并及时更新哈希环。
对节点问题的分析如下:
假定服务CACHEB是在群集中启动的,并且服务器的IP地址仅在Key1和Cachea之间映射。然后,与Key1相对应的用户每次发送消息时,与Key1运行相对应以发送消息。结果显然不是消息,因为Cacheb没有对应于Key1的相应会话的会话。
我们目前有两种解决方案。
计划A很简单,动作很大:
尤里卡(Eureka)听到节点UP事件后,根据现有群集信息进行了更新哈希环。并断开所有会话连接以重新连接客户端。目前,客户端将连接到更新的哈希链接节点,以避免无法传递消息的情况。
计划B复杂,运动很小:
让我们看一下没有虚拟节点的情况。假设服务器CACHEB是在CACHEC和缓存之间启动的。当所有将所有用户映射到CACHEC到Cacheb时,他们将消息发送到发送消息时,他们会转到Cacheb。在CACHEC到CACHEB之间。因此,我们只需要断开缓存即可断开与CACHEB用户相对应的用户会话的连接,即可再次使客户端。
接下来是虚拟节点的情况,假设浅色节点是虚拟节点。我们使用长括号来表示属于某个缓存区域的某个区域的结果。首先是c节点不是的情况启动。每个人都应该了解B的所有B虚拟节点都将指向真实的B节点,因此所有B节点都将映射到顺时针的逆时针部分中的B(因为我们规定了Hash正在搜索顺时针方向)。
接下来是节点C的情况。您可以看到某些区域已被C占据。
在上述情况下,我们可以知道,将同时在线有许多相应的虚拟节点,因此我们需要断开与与相应会话相对应的会话相对应的会话连接(上图的红色部分)。特定算法有点复杂,实施方法因人而异。您可以尝试自己实现算法。
哈希环应放在哪里?
此时,已经设置了我们的Spring Websocket集群。最重要的地方是一致性哈希算法。如何根据WS请求向指定的群集服务器前进?
答案在于负载平衡。SpringCloud Gateway或Zuul均默认为色带作为负载平衡。我们只需要根据客户ID的用户ID来重写功能区负载平衡算法时,当WS请求建立时,请将WS请求重新发布到IP。该过程如下图所示:
当用户交流时,他们只需要根据ID执行哈希,并在哈希环上获取相应的IP,并且在与用户设置WS连接时,您可以知道哪个服务器!
在实际操作期间,受试者在色带中发现了两个不完整的位置...
有没有办法这样做?实际上,还有另一种可行和临时替代的方法!
如下图所示,客户端将普通的HTTP请求(包括ID参数)发送到网关。该网关是根据ID的Hash,在哈希环中找到IP地址,将IP地址返回给客户端,然后将根据IP根据IPThe地址的地址,由WS请求。
因为功能区并没有完善钥匙的处理,所以我们暂时无法在功能区实现一致性哈希算法。它只能由客户端(HTTP,一个WS)间接启动,以实现一致性哈希。不久之后,缺陷!让我们的Websocket群集变得更加优雅。
以上是我探索的结果。在此期间,遇到了许多问题,并且问题一个人列出了两个Websocket群集解决方案。第一个是会话广播,第二个是一致性哈希。
这两个方案在不同情况下具有优势和缺点。本文不使用诸如ActiveMQ,Karfa等的消息队列,而只是想使用自己的想法,而不依靠消息队列来简单地意识到多个用户之间的长时间连接通信。Sessencei希望为您提供一个不寻常的想法。
作者:Qiu Chengzheng
资料来源:https://sementfault.com/a/1190000017307713