cover_image

WebSocket协议在作业系统的落地实践

不吃鱼的猫 拍码场
2024年12月25日 02:09

WebSocket是什么?

WebSocket 是一种网络通信协议,提供了在单个TCP连接上进行全双工通信的能力。它允许服务器和客户端之间建立一个持久的连接,并通过这个连接实时地发送和接收数据。

图片

WebSocket VS HTTP

图片

WebSocket工作流程

WebSocket 工作流程大致可以分为以下几个步骤:

1.客户端发起请求:客户端通过HTTP发送一个带有特殊头部的请求到服务器,请求升级到WebSocket协议。

2.服务器接收请求:服务器接收到客户端的请求后,检查是否支持WebSocket。

3.握手过程:如果服务器支持WebSocket,它将发送一个握手响应,包含Sec-WebSocket-Accept头部,这是对客户端Sec-WebSocket-Key的加密确认。

4.连接建立:客户端验证服务器的Sec-WebSocket-Accept头部,如果验证成功,握手完成,WebSocket连接建立。

5.数据传输:连接建立后,客户端和服务器可以开始发送和接收数据帧。

6.帧编码:数据在发送前被编码,可能包括掩码和压缩。

7.帧传输:编码后的数据帧通过网络传输。

8.帧解码:接收端收到数据帧后,进行解码,去除掩码和解压缩。

9.数据处理:解码后的数据帧被传递给应用程序进行处理。

10.关闭连接:任何一方都可以通过发送关闭帧来关闭WebSocket连接。

11.连接关闭:一旦关闭帧被发送并确认,WebSocket连接就正式关闭。

图片

在线聊天应用

技术选型

特性NettyT-IO
社区活跃度高,拥有广泛的用户基础和开发者社区相对较低,但提供了丰富的示例和文档
API设计功能丰富,但相对复杂易懂,尽量避免引入自创概念,降低学习成本
性能高性能,尤其在处理大量并发连接时表现出色性能良好,但在某些测试中可能不如Netty
资源管理需要手动管理资源内置业务数据管理能力,简化资源绑定与释放
协议支持支持多种协议,包括HTTP、WebSocket、FTP、SMTP等官方提供的协议支持较少,主要为HTTP和WebSocket
线程模型异步非阻塞,基于Reactor模式同步安全线程池,简化内部调度线程
内存管理可能需要更细致的内存管理自创同步安全线程池,减少内存管理复杂性
易用性功能强大,但学习曲线较陡易学,API设计让工程师用起来舒服
文档和示例文档丰富,但可能难以理解提供了生产级别的showcase示范工程
跨平台支持多种操作系统未明确说明,但通常Java框架具有跨平台特性

基于以上比对,需要高性能,文档完善,功能丰富的组件,因此我们选择使用Netty作为我们的WebSocket服务器框架。

Netty架构

图片

Netty WebSocket的工作流程可以分为以下几个步骤:

1.初始化服务器:创建ServerBootstrap实例,配置线程模型、通道类型等。

2.设置线程池:通过group方法设置事件循环组,通常使用NioEventLoopGroup类型,分为Boss线程组和Worker线程组。

3.配置通道和处理器:调用channel方法指定通道类型,如NioServerSocketChannel,并通过childHandler方法设置通道处理器(ChannelInitializer),用于初始化新连接的Channel,并添加业务逻辑处理器(ChannelHandler)。

图片

4.绑定端口:通过bind方法绑定监听端口,并调用sync方法等待绑定完成。

5.处理连接:一旦有客户端连接到服务器端口,Boss线程会接收到连接事件,创建新的SocketChannel并将其注册到Worker线程组的事件循环中。

6.事件循环处理:Worker线程会不断循环从注册的SocketChannel中读取数据,并将数据交给ChannelPipeline中的ChannelHandler处理。处理完成后,可以向客户端发送响应数据。

7.WebSocket握手:在ChannelInitializer中添加HttpServerCodec和WebSocketServerProtocolHandler,用于处理WebSocket握手和消息传输。

图片

8.数据传输:握手成功后,客户端和服务器之间可以开始发送和接收WebSocket消息。

9.关闭连接:任何一方都可以通过发送关闭帧来关闭WebSocket连接。

10.优雅关闭:调用shutdownGracefully方法优雅地关闭EventLoopGroup,释放所有的资源。

图片

这个流程涵盖了从服务器初始化到WebSocket连接建立、数据传输以及连接关闭的全过程。通过Netty的事件驱动模型,可以高效地处理大量并发WebSocket连接。

系统部署图

图片

架构图

图片

用例图

图片

netty作为消息引擎负责投递消息到各个客户端client

1.customer1通过ng链接任意一台server, 如server1. agent1连接server2

2.保存客户端和服务端的连接信息到 redis, uid <--> hostip。保存 uid <--> channel 本地缓存(使用BiMap实现)。持久化消息成功后返回发送成功,否则返回发送失败,客户端重发该消息。

3.customer1 <-> server1 保持长连接,customer1 开启心跳,上报活动状态。服务端也开启心跳,剔除长时间没有心跳的客户端。

4.customer1发送msg1到server1。

5.服务端根据消息toId找到agent1,判断agent1的长连接是否存在

存在则通过本地BiMap获取对应channel, 通过channel把消息写出去。

不存在则通过redis获取对应host, 通过host + url 把消息转发到服务端上server2。

6.server2消费请求,通过BiMap获取agnet1的channel, 写收到的消息进该channel.

消息发送接收

图片

消息HA投递

图片

1.发送消息时先生成msgId, msgId采用数据库主键

2.server收到消息后直接推送对应的聊天对象,

3.发送该消息到mq系统

4.普通消息通过发送消息触发投递。

5.客户端收到消息后,发送ack消息。

6.服务端收到ack消息,记录该消息已读。

7.每台实例消费mq消息,判断是否已读。如未读重新投递消息。

8.重复#6

功能展示

图片

总结

WebSocket 协议的全双工特性允许客户端和服务器实时、双向地交换数据,这使得它非常适合需要实时交互的应用,如在线游戏、聊天应用、股票行情更新等。

作者介绍

不吃鱼的猫,信也科技后端研发

招聘信息


信也科技 · 目录
上一篇AI Agent在知识挖掘领域的落地实践——信安小卫士下一篇RTA从ECS转向容器化架构演进
继续滑动看下一个
拍码场
向上滑动看下一个