百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

SpringBoot生产级WebSocket集群实践,支持10万连接!

off999 2025-03-19 01:02 31 浏览 0 评论

1、问题背景

智慧门诊系统旨在从一定程度上解决患者面临的三长一短(挂号、看病、取药时间长,医生问诊时间短)的问题。实现“诊前、诊中、诊后”实时智能一体化,整合完善医院工作流程。围绕门诊看病的各个环节,让患者全程手机有提醒,让患者少排队、少跑腿、看病更简单,获得全流程的陪伴服务从而有效提升就医体验。

系统通过接收医院第三方系统推送的门诊数据,再结合业务服务处理后主动推送到前端,从而实时的将数据同步给患者手机。之所以没有采用传统的前端轮训方案,主要是在当前业务场景下存在时效性不足,资源浪费等问题。但与此同时也有代价的,相比于Http的无状态通信,服务端主动推送是有状态协议的,客户端连接服务器时只和集群中一个节点连接,数据传输过程中也只与这一节点通信,在集群多台服务器环境下,我们就出现了服务端部分消息推送丢失的现象。

当前架构图如下:


2、问题分析和整体思路

客户端和服务端每次建立连接时候,会创建有状态的会话Session,服务器得保存维持连接的Session。客户端每次只能和集群服务器其中的一个服务器连接,后续也是和该服务器进行数据传输。因此集群的问题,应该考虑Session的问题,客户端成功连接服务器之后,其他服务器也知道客户端连接成功。

可以使用Nginx负载均衡的ip hash算法,客户端每次都是请求同一个服务器,客户端的session都保存在该服务器上,而后续请求都是请求该服务器,都能获取到session,就不存在分布式session问题了。websocket相对http来说,可以由服务端主动推动消息给客户端,如果接收消息的服务端和发送消息消息的服务端不是同一个服务端,发送消息的服务端无法找到接收消息对应的session,即两个session不处于同一个服务端,也就无法推送消息。

解决问题的方法是将所有消息的发送方和接收方都处于同一个服务器下,而消息发送方和接收方都是不确定的,显然是无法实现的。将消息的发送方和接收方都处于同一个服务器下才能发送消息,那么可以转换一下思路,可以将消息以消息广播的方式通知给所有的服务器,可以使用消息中间件发布订阅模式,消息脱离了服务器的限制,通过发送到中间件,再发送给订阅的服务器,类似广播一样,只要订阅了消息,都能接收到消息的通知。

3、解决方案

WebSocket协议是基于TCP的一种新的网络协议,是一个应用层协议,是 HTML5 提供的一种在单个 TCP 连接上进行全双工通讯的协议,与 TCP 一样,客户端和服务器都可以随时向对方发送数据,而不用像 HTTP请求 - 应答”通信模式。于是,服务器就可以变得更加“主动”了。一旦后台有新的数据,就可以立即“推送”给客户端,不需要客户端轮询,“实时通信”的效率也就提高了。

浏览器是一个“沙盒”环境,有很多的限制,不允许建立 TCP 连接收发数据,而WebSocket利用了 HTTP 本身的“协议升级”特性,“伪装”成 HTTP,这样就能绕过浏览器沙盒、与服务器直接建立“TCP 连接”,获得更多的自由。

一个典型的 Websocket 握手请求如下:

1、客户端请求

2、服务器回应

WebSocket是有状态的,无法像直接HTTP以集群方式实现负载均衡,长连接建立后即与服务端某个节点保持着会话,因此集群下想要得知会话属于哪个节点,有两种方案,一种是使用类似微服务的注册中心来维护全局的会话映射关系,一种是使用事件广播由各节点自行判断是否持有会话,两种方案对比如表所示。

综合考虑实现成本与集群规模,选择了轻量级的事件广播方案。实现广播可以选择基于RocketMQ的消息广播、基于Redis的Publish/Subscribe、基于服务的通知等方案,其优缺点对比如表所示。从实时性、实现难易等方面考虑,同时对于持久化高可靠级别并没有太高要求,最终选择了Redis。

改造后架构图如下:

4、核心实现

基于spring boot建立websocket连接

基于spring boot接收 websocket消息

基于spring boot发布和订阅Redis消息

vue前端websocket建立连接、心跳检测、发送消息、消息订阅等

Nginx反向代理配置

5、性能测试

性能压测选择两台配置为2核16G的虚拟机,分别作为服务器和客户端。压测时选择为网关开放了5个端口,同时建立5个客户端,每个客户端使用一个服务端端口建立起2万连接,可以同时创建10万个连接。连接数与内存使用情况如图所示。

给10万个长连接同时发送一条消息,采用单线程发送,服务器发送完成的平均耗时在10s左右,如图所示。

当前的性能指标已满足智慧门诊的实际业务场景,可支持未来的业务增长。

6、产品效果


7、问题和展望

当前WebSocket实现分散在在各个服务中,与业务系统强耦合,如果有其他业务需要集成WebSocket,面临着重复开发的窘境,浪费成本、效率低下。后续建议在网关中扩展统一集成管理websocket,能够具备以下特点:

  1. 集中实现长连接管理和推送能力。统一技术栈,将长连接作为基础能力沉淀,便于功能迭代和升级维护。
  2. 与业务解耦。将业务逻辑与长连接通信分离,使业务系统不再关心通信细节,也避免了重复开发,浪费研发成本。
  3. 使用简单。提供HTTP推送通道,方便各种开发语言的接入。业务系统只需要简单的调用,就可以实现数据推送,提升研发效率。
  4. 分布式架构。实现多节点的集群,支持水平扩展应对业务增长带来的挑战;节点宕机不影响服务整体可用性,保证高可靠。
  5. 多端消息同步。允许用户使用多个浏览器或标签页同时登陆在线,保证消息同步发送。
  6. 多维度监控与报警。自定义监控指标与现有微服务监控系统打通,出现问题时可及时报警,保证服务的稳定性。

来源:
https://mp.weixin.qq.com/s/whdDS-k0JVXo_dRGqDo0Rw

相关推荐

Python钩子函数实现事件驱动系统(created钩子函数)

钩子函数(HookFunction)是现代软件开发中一个重要的设计模式,它允许开发者在特定事件发生时自动执行预定义的代码。在Python生态系统中,钩子函数广泛应用于框架开发、插件系统、事件处理和中...

Python函数(python函数题库及答案)

定义和基本内容def函数名(传入参数):函数体return返回值注意:参数、返回值如果不需要,可以省略。函数必须先定义后使用。参数之间使用逗号进行分割,传入的时候,按照顺序传入...

Python技能:Pathlib面向对象操作路径,比os.path更现代!

在Python编程中,文件和目录的操作是日常中不可或缺的一部分。虽然,这么久以来,钢铁老豆也还是习惯性地使用os、shutil模块的函数式API,这两个模块虽然功能强大,但在某些情况下还是显得笨重,不...

使用Python实现智能物流系统优化与路径规划

阅读文章前辛苦您点下“关注”,方便讨论和分享,为了回馈您的支持,我将每日更新优质内容。在现代物流系统中,优化运输路径和提高配送效率是至关重要的。本文将介绍如何使用Python实现智能物流系统的优化与路...

Python if 语句的系统化学习路径(python里的if语句案例)

以下是针对Pythonif语句的系统化学习路径,从零基础到灵活应用分为4个阶段,包含具体练习项目和避坑指南:一、基础认知阶段(1-2天)目标:理解条件判断的逻辑本质核心语法结构if条件:...

[Python] FastAPI基础:Path路径参数用法解析与实例

查询query参数(上一篇)路径path参数(本篇)请求体body参数(下一篇)请求头header参数本篇项目目录结构:1.路径参数路径参数是URL地址的一部分,是必填的。路径参...

Python小案例55- os模块执行文件路径

在Python中,我们可以使用os模块来执行文件路径操作。os模块提供了许多函数,用于处理文件和目录路径。获取当前工作目录(CurrentWorkingDirectory,CWD):使用os....

python:os.path - 常用路径操作模块

应该是所有程序都需要用到的路径操作,不废话,直接开始以下是常用总结,当你想做路径相关时,首先应该想到的是这个模块,并知道这个模块有哪些主要功能,获取、分割、拼接、判断、获取文件属性。1、路径获取2、路...

原来如此:Python居然有6种模块路径搜索方式

点赞、收藏、加关注,下次找我不迷路当我们使用import语句导入模块时,Python是怎么找到这些模块的呢?今天我就带大家深入了解Python的6种模块路径搜索方式。一、Python模块...

每天10分钟,python进阶(25)(python进阶视频)

首先明确学习目标,今天的目标是继续python中实例开发项目--飞机大战今天任务进行面向对象版的飞机大战开发--游戏代码整编目标:完善整串代码,提供完整游戏代码历时25天,首先要看成品,坚持才有收获i...

python 打地鼠小游戏(打地鼠python程序设计说明)

给大家分享一段AI自动生成的代码(在这个游戏中,玩家需要在有限时间内打中尽可能多的出现在地图上的地鼠),由于我现在用的这个电脑没有安装sublime或pycharm等工具,所以还没有测试,有兴趣的朋友...

python线程之十:线程 threading 最终总结

小伙伴们,到今天threading模块彻底讲完。现在全面总结threading模块1、threading模块有自己的方法详细点击【threading模块的方法】threading模块:较低级...

Python信号处理实战:使用signal模块响应系统事件

信号是操作系统用来通知进程发生了某个事件的一种异步通信方式。在Python中,标准库的signal模块提供了处理这些系统信号的机制。信号通常由外部事件触发,例如用户按下Ctrl+C、子进程终止或系统资...

Python多线程:让程序 “多线作战” 的秘密武器

一、什么是多线程?在日常生活中,我们可以一边听音乐一边浏览新闻,这就是“多任务处理”。在Python编程里,多线程同样允许程序同时执行多个任务,从而提升程序的执行效率和响应速度。不过,Python...

用python写游戏之200行代码写个数字华容道

今天来分析一个益智游戏,数字华容道。当初对这个游戏颇有印象还是在最强大脑节目上面,何猷君以几十秒就完成了这个游戏。前几天写2048的时候,又想起了这个游戏,想着来研究一下。游戏玩法用尽量少的步数,尽量...

取消回复欢迎 发表评论: