springBoot + netty搭建高性能 websocket 服务 & 性能测试

一、前言

1、如果我们的app类似于股票这种,数据很多很快,之前用的tomcat自带的websocket 又或者 spring-boot-starter-websocke集成,但是性能在数据并发很大时就会存在问题。

2、我前面写的一篇关于 springBoot+webosket的,没有使用netty的文章 springBoot使用webSocket的几种方式以及在高并发出现的问题及解决 ,其中就包含了 以下者两种方式,都有说明,大家如果量不大,下面这两种方式也是可以的。

  • tomcat自带的websocket
  • spring-boot-starter-websocke集成

二、使用Netty 完成 webSocket

1、如何使用 ,可以参考 netty + webSocket + SpringBott 是参考文章 SpringBoot整合Netty处理WebSocket(支持url参数) 这篇文章是,说的已经很ok了,我这里主要加上一些个人的理解,以及注释说明

2.1、RequestUriUtils 的 getBasePath 方法

2、比如你的链接是 ws://192.168.172.139:1234/ws/id=1,使用它文章中的获取后得到 /ws/,建议改成如下,获取之后是 /ws

    /**
     * 获取URI中参数以外部分路径
     *
     * @param uri
     * @return
     */
    public static String getBasePath(String uriStr) {
        String pathWithSlash ="";
        try {
            // 使用URI解析URL字符串
            URI uri = new URI(uriStr);
            // 获取路径部分
            pathWithSlash = uri.getPath();
            // 去掉末尾的斜杠
            return pathWithSlash.replaceAll("/$", "");
        } catch (URISyntaxException e) {
            log.error("解析path错误", e);
        }
        return pathWithSlash;
    }

2.2、WebSocketChannelInitializer 中的 ChannelPipeline 说明

在WebSocket服务器的构建中添加.addLast(new HttpServerCodec())的主要原因是WebSocket握手是基于HTTP协议的,WebSocket连接的建立需要经过以下步骤:

  1. 客户端向服务器发送一个HTTP请求,请求升级到WebSocket协议。
  2. 服务器收到这个请求后,需要进行协议升级处理,将HTTP协议切换到WebSocket协议。
  3. 一旦升级成功,WebSocket连接建立,客户端和服务器之间可以通过WebSocket协议进行双向通信。

因此,WebSocket握手的开始阶段仍然是HTTP请求和响应。为了处理这个初始的HTTP请求,需要在Netty的ChannelPipeline中添加.addLast(new HttpServerCodec()),以确保能够解析和处理这个HTTP请求,并在需要时将其升级为WebSocket连接。简而言之,.addLast(new HttpServerCodec())的作用是为了使WebSocket服务器能够正确地处理WebSocket握手之前的HTTP请求和响应,确保WebSocket连接能够成功建立。一旦WebSocket连接建立,就可以通过WebSocket协议进行实时双向通信。

这是WebSocket服务器构建中的一个标准操作。websocket协议本身是基于http协议的,所以这边也要使用http解编码器

2.3、addLast(new ChunkedWriteHandler())

.addLast(new ChunkedWriteHandler()) 是 Netty 中的一个 ChannelHandler,它的主要作用是支持异步写大数据流(例如文件传输)。

在某些情况下,你可能需要向客户端发送大量的数据,例如文件的内容,而不是一次性将整个数据写入缓冲区,因为这可能会导致内存占用过高。相反,你可以将数据分成小块(chunk)并逐块写入客户端,以避免内存问题。

ChunkedWriteHandler 的作用如下:

  1. 支持大数据流的异步写入: 它允许你将数据切割成小块并异步地将这些块写入客户端。这对于传输大型文件或大量数据非常有用,因为它可以避免将整个数据加载到内存中。
  2. 维护写入顺序: 它确保数据块按照它们添加到 Channel 的顺序进行写入。这有助于保持数据的有序性。
  3. 提高性能: 通过异步写入数据块,ChunkedWriteHandler 可以提高网络性能,因为它不会阻塞线程等待数据传输完成。

这个处理器通常与其他处理器一起使用,以完成完整的数据传输过程。例如,如果你要实现文件传输,通常会使用 ChunkedWriteHandler 将文件数据切割成小块,然后使用其他处理器来处理文件的传输,例如文件块的编码和解码。
总之,.addLast(new ChunkedWriteHandler()) 的作用是支持异步写大数据流,以提高性能并降低内存使用,尤其在需要传输大量数据时非常有用。

2.4、addLast(new HttpObjectAggregator(1024 * 64))

将HttpMessage和HttpContents聚合到一个完成的 FullHttpRequest或FullHttpResponse中,具体是FullHttpRequest对象还是FullHttpResponse对象取决于是请求还是响应

.addLast(new HttpObjectAggregator(1024 * 64)) 是 Netty 中的一个 ChannelHandler,主要用于将HTTP请求或响应的多个部分聚合成一个完整的HTTP消息。这对于处理HTTP消息非常有用,特别是当你需要处理大量的HTTP数据时。

以下是.addLast(new HttpObjectAggregator(1024 * 64))的主要作用:

  1. 消息聚合: 在HTTP通信中,请求或响应可能会分成多个部分(例如,HTTP请求头和HTTP请求体)。HttpObjectAggregator 负责将这些部分聚合成一个完整的FullHttpRequestFullHttpResponse,以便更容易处理和操作。
  2. 内存管理: 这个处理器还具有内存管理功能。你可以在构造函数中指定一个最大的聚合字节数(在示例中是64 KB)。如果接收到的HTTP数据超过了这个大小,HttpObjectAggregator 将抛出异常以防止内存泄漏。
  3. 简化HTTP消息处理: 聚合HTTP消息使得你可以更容易地处理完整的HTTP请求和响应,而不必手动处理每个部分。这对于构建Web服务器或HTTP代理非常有用。

示例使用:

pipeline.addLast(new HttpServerCodec()); // 添加HTTP编解码器
pipeline.addLast(new HttpObjectAggregator(1024 * 64)); // 聚合HTTP消息,最大64KB
pipeline.addLast(new MyHttpRequestHandler()); // 自定义的HTTP请求处理器

在上面的示例中,首先使用 HttpServerCodec 添加了HTTP编解码器,然后使用 HttpObjectAggregator 聚合HTTP消息,最后添加了一个自定义的HTTP请求处理器。
总之,.addLast(new HttpObjectAggregator(1024 * 64)) 的作用是将HTTP请求或响应的多个部分聚合成一个完整的HTTP消息,以简化和改善处理HTTP消息的流程,并提供内存管理功能。这在构建支持HTTP的应用程序中非常有用。

2.5、addLast(new WebSocketServerCompressionHandler())

webSocket 数据压缩扩展,当添加这个的时候WebSocketServerProtocolHandler的第三个参数需要设置成true
.addLast(new WebSocketServerCompressionHandler()) 是 Netty 中的一个 ChannelHandler,用于支持 WebSocket 消息的压缩和解压缩。WebSocket 消息压缩可以减小消息的大小,提高网络传输效率,尤其在低带宽环境下非常有用。

以下是 .addLast(new WebSocketServerCompressionHandler()) 的主要作用:

  1. WebSocket 消息压缩: 当客户端和服务器之间通过 WebSocket 协议传输大量数据时,可以使用压缩技术将消息压缩为更小的尺寸,以减少网络带宽的使用。WebSocketServerCompressionHandler 负责处理消息的压缩。
  2. WebSocket 消息解压缩: 对于接收到的已压缩的 WebSocket 消息,服务器需要将其解压缩以获取原始消息。WebSocketServerCompressionHandler 也负责解压缩已压缩的消息。
  3. 支持多种压缩算法: WebSocketServerCompressionHandler 支持多种压缩算法,包括通常的 DEFLATE 和 GZIP 压缩算法,以及自定义的压缩算法。

在WebSocket应用程序中,通常需要在WebSocket连接建立时协商是否启用压缩,以及使用哪种压缩算法。如果客户端和服务器都支持压缩,那么它们可以在消息传输过程中启用压缩。

要使用 .addLast(new WebSocketServerCompressionHandler()),你需要在 WebSocket 服务器的处理管道中添加该处理器。例如:

pipeline.addLast(new HttpServerCodec()); // 添加HTTP编解码器
pipeline.addLast(new HttpObjectAggregator(1024 * 64)); // 聚合HTTP消息,最大64KB
pipeline.addLast(new WebSocketServerCompressionHandler()); // 添加WebSocket消息压缩处理器
pipeline.addLast(new MyWebSocketHandler()); // 自定义的WebSocket处理器

在上面的示例中,首先使用 HttpServerCodec 添加了HTTP编解码器,然后使用 HttpObjectAggregator 聚合HTTP消息,接下来添加了 WebSocketServerCompressionHandler 以支持WebSocket消息压缩,最后添加了一个自定义的WebSocket处理器。

总之,.addLast(new WebSocketServerCompressionHandler()) 的作用是为WebSocket服务器添加消息压缩和解压缩的功能,以减小消息大小并提高网络传输效率。这在需要传输大量数据的WebSocket应用中非常有用。

2.6、.addLast(new MyWebSocketHandler())

自定义处理器 - 处理 web socket 消息(消息的父类是WebSocketFrame,旗下有很多子类,比如BinaryWebSocketFrame TextWebSocketFrame 等等)

如果你使用的是 父类是WebSocketFrame,则需要在其内部,判断是什么类型的数据,如果你使用的具体的子类,那么只有具体的消息类型会到哪里

2.7、 .addLast(new WebSocketServerProtocolHandler(WebSocketProperties.path, null, true, 10485760));

服务器端向外暴露的 web socket 端点,当客户端传递比较大的对象时,maxFrameSize参数的值需要调大

WebSocketServerProtocolHandler 是 Netty 中的一个关键组件,用于处理 WebSocket 握手和协议升级,以及管理 WebSocket 连接的生命周期。它的主要作用如下:

  1. WebSocket 握手处理: 当客户端通过 HTTP 请求发起 WebSocket 握手时,WebSocketServerProtocolHandler 负责识别并处理这些握手请求。它可以检查HTTP请求中的升级标头和协议头,以确定是否需要升级到 WebSocket 协议。
  2. WebSocket 握手协议升级: 如果客户端发送了符合 WebSocket 握手规范的请求,WebSocketServerProtocolHandler 会处理协议升级,将连接从 HTTP 协议切换到 WebSocket 协议。这个过程包括升级响应的构建和升级握手的处理。
  3. WebSocket 生命周期管理: 一旦 WebSocket 握手成功,WebSocketServerProtocolHandler 管理 WebSocket 连接的生命周期。它会处理连接的打开、关闭、异常和消息传递等事件。
  4. Ping/Pong 处理: WebSocket 协议支持 Ping 和 Pong 消息,用于保持连接的活动状态。WebSocketServerProtocolHandler 会自动处理这些心跳消息,以确保连接保持活动状态。

以下是一个示例,展示了如何在 Netty 中使用 WebSocketServerProtocolHandler

pipeline.addLast(new HttpServerCodec()); // 添加HTTP编解码器
pipeline.addLast(new HttpObjectAggregator(1024 * 64)); // 聚合HTTP消息,最大64KB
pipeline.addLast(new WebSocketServerProtocolHandler("/websocket")); // 添加WebSocket握手处理器
pipeline.addLast(new MyWebSocketHandler()); // 自定义的WebSocket处理器

在上面的示例中,WebSocketServerProtocolHandler 被添加到处理管道中,并指定了 WebSocket 的路径(在示例中是"/websocket")。一旦握手成功,连接将切换到 WebSocket 协议,并且可以在 MyWebSocketHandler 中处理 WebSocket 消息。

总之,WebSocketServerProtocolHandler 是用于处理 WebSocket 握手和协议升级的关键组件,它使得在 Netty 中创建 WebSocket 服务器变得更加容易。

三、Web Socket 性能对比——Spring Boot vs Tomcat vs Netty

参考文章 Web Socket 性能对比——Spring Boot vs Tomcat vs Netty 说的很ok了。

四、使用四种框架分别实现百万websocket常连接的服务器(写的很好,必看)

1、文章包含了一些线上的参数调整,都是干活
原文地址: https://colobu.com/2015/05/22/implement-C1000K-servers-by-spray-netty-undertow-and-node-js/

五、七种WebSocket框架的性能比较

原文地址: https://colobu.com/2015/07/14/performance-comparison-of-7-websocket-frameworks/

你可能感兴趣的:(netty,spring,boot,websocket,后端)