Netty 核心原理:手把手搭建高性能 HTTP 服务器

IT巴士 68 0

Netty 是基于 Java NIO 技术构建的网络应用框架,它就像一个功能强大的“网络工具箱”,具备异步非阻塞、事件驱动以及高度可定制等诸多优秀特性。相较于传统的 Java 网络编程方式,Netty 巧妙地简化了网络编程中那些复杂繁琐的部分,让咱们开发者能够把更多的精力投入到业务逻辑的实现上。

异步非阻塞:高效运转的“秘密武器”

Netty 的异步非阻塞特性,堪称其实现高性能的“秘密武器”。在传统的阻塞式 I/O 模型里,线程一旦进行 I/O 操作,就会像被施了定身咒一样被阻塞住,只能乖乖等待操作完成。这就好比一个人在做一件事的时候,必须等这件事彻底做完才能去做下一件,导致线程的利用率非常低,面对大量并发请求时,就会显得力不从心。

而 Netty 基于 NIO(Non - blocking I/O)技术,情况就大不一样啦。线程在进行 I/O 操作时,不会再被死死地“钉”在那里,而是可以灵活地去处理其他任务。打个比方,当一个线程要向 Channel 写入数据时,它不需要一直守在那里等着数据全部写完,而是可以潇洒地转身去做别的事情,就像我们把一封信投进邮箱后,不用一直站在邮箱旁边等它被寄走,完全可以去做其他有意义的事。这种异步非阻塞的工作方式,极大地提升了系统处理并发请求的能力,让服务器能够轻松应对海量的网络连接。

事件驱动:有条不紊的“调度中心”

Netty 采用的事件驱动设计模式,就像是一个有条不紊的“调度中心”。它把各种网络操作精心包装成一个个不同的事件,比如连接成功建立的事件、有数据可读的事件、数据可以写入的事件等等。一旦这些事件发生,Netty 就会像一个精准的“传令官”,迅速把事件通知给对应的 ChannelHandler,由 ChannelHandler 来具体处理这些事件。

这种事件驱动的机制,使得 Netty 能够高效地应对各种复杂多变的网络事件,实现流畅的异步非阻塞通信。想象一下,服务器就像一个热闹的大商场,各种网络事件就如同商场里来来往往的顾客和发生的各种情况,而 Netty 的事件驱动机制就像是商场里训练有素的管理人员,能够及时发现并处理各种“状况”,确保整个商场(服务器)的正常运转。

Netty 核心组件全解析

在正式动手实现 HTTP 服务器之前,咱们得好好了解一下 Netty 的几个核心组件,它们可是构建 Netty 应用的“基石”。

Channel:网络连接的“虚拟桥梁”

Channel 是 Netty 对网络连接的一种抽象表示,它就像是一座“虚拟桥梁”,连接着服务器和客户端。通过 Channel,我们可以进行各种各样的 I/O 操作,比如使用 bind() 方法绑定端口,connect() 方法建立连接,read() 方法读取数据,write() 方法写入数据等等。

举个例子,在服务器端,当有客户端发起连接请求时,就会创建一个 Channel。这个 Channel 就像是一条专门为这个客户端开辟的“数据通道”,服务器可以通过它把接收到的客户端数据读取出来,也可以把处理好的响应数据通过这个“通道”发送给客户端,实现双方的数据交互。

EventLoop:默默耕耘的“幕后英雄”

EventLoop 是 Netty 异步事件驱动的核心“功臣”,它负责处理 Channel 上的 I/O 操作和各种事件。一个 EventLoop 在它的整个生命周期里,只能和一个 Thread 紧密绑定在一起,而一个 Channel 在其“一生”中,也只能注册到一个 EventLoop 上。

当有新的连接到达时,Netty 会为这个连接注册一个 Channel,然后从 EventLoopGroup 中挑选一个合适的 EventLoop 分配给这个 Channel。在这个 Channel 的整个使用过程中,都由这个被分配的 EventLoop 来“保驾护航”,为它处理各种事务。EventLoop 就像一个不知疲倦的“幕后英雄”,一直在后台不断循环,时刻监听着 Channel 上发生的各种事件。一旦有事件发生,它就会迅速调用相应的 ChannelHandler 来进行处理,确保网络通信的顺畅进行。

ChannelPipeline:数据处理的“流水线”

ChannelPipeline 是 ChannelHandler 的“大容器”,它的作用是管理和安排 ChannelHandler 的执行顺序。ChannelPipeline 就如同一条高效运转的“流水线”,数据在这条“流水线”中有序流动,依次经过各个 ChannelHandler 的“加工处理”。

我们可以根据实际需求,在 ChannelPipeline 中添加各种各样的 ChannelHandler,比如编码器、解码器、专门处理业务逻辑的处理器等等。这些不同功能的 ChannelHandler 就像流水线上不同工序的工人,各自负责对数据进行特定的处理,最终让数据以我们期望的形式在网络中传输。

ChannelHandler:业务逻辑的“实现舞台”

ChannelHandler 是实现具体业务逻辑的关键“舞台”。它又细分为入站处理器(ChannelInboundHandler)和出站处理器(ChannelOutboundHandler)。入站处理器主要负责处理从网络中接收到的数据,就像是工厂的原材料检验员,对接收到的“原材料”(数据)进行检查和处理;而出站处理器则负责处理要发送到网络中的数据,类似于产品包装员,把处理好的“产品”(数据)进行包装,准备发送出去。

比如说,我们可以实现一个入站处理器,专门用来解析接收到的 HTTP 请求,把请求中的各种信息提取出来;再实现一个出站处理器,负责精心构建要发送给客户端的 HTTP 响应,确保响应数据的格式正确、内容完整。

从零开始搭建高性能 HTTP 服务器

引入 Netty 依赖

要使用 Netty 来搭建我们的 HTTP 服务器,首先得在项目里引入 Netty 的相关依赖。如果我们使用的是 Maven 项目管理工具,那就需要在 pom.xml 文件里添加下面这段依赖代码:

<dependency>     
    <groupId>io.netty</groupId>      
    <artifactId>netty - all</artifactId>     
    <version>4.1.77.Final</version> 
</dependency>

这段代码就像是给我们的项目“打开了一扇门”,让项目能够顺利使用 Netty 提供的各种功能和工具。

创建服务器启动类

接下来,咱们创建一个服务器启动类,这个类的作用就是把 Netty HTTP 服务器“发动”起来。

import io.netty.bootstrap.ServerBootstrap;  
import io.netty.channel.ChannelFuture;  
import io.netty.channel.ChannelInitializer;  
import io.netty.channel.ChannelOption;  
import io.netty.channel.EventLoopGroup;  
import io.netty.channel.nio.NioEventLoopGroup;  
import io.netty.channel.socket.SocketChannel;  
import io.netty.channel.socket.nio.NioServerSocketChannel;  
import io.netty.handler.codec.http.HttpObjectAggregator;  
import io.netty.handler.codec.http.HttpServerCodec;  
 public class HttpServer { 
    private static final int PORT = 8080; 
     public static void main(String[] args) throws Exception { 
        // 创建两个 EventLoopGroup,一个负责处理连接建立,一个负责处理 I/O 操作         
        EventLoopGroup bossGroup = new NioEventLoopGroup(1); 
        EventLoopGroup workerGroup = new NioEventLoopGroup(); 
         try { 
            ServerBootstrap bootstrap = new ServerBootstrap(); 
            bootstrap.group(bossGroup,  workerGroup) 
                 .channel(NioServerSocketChannel.class)  
                 .option(ChannelOption.SO_BACKLOG, 128) 
                 .childOption(ChannelOption.SO_KEEPALIVE, true) 
                 .childHandler(new ChannelInitializer<SocketChannel>() { 
                        @Override                         protected void initChannel(SocketChannel ch) throws Exception { 
                            ch.pipeline().addLast(new  HttpServerCodec()); 
                            ch.pipeline().addLast(new  HttpObjectAggregator(65536)); 
                            ch.pipeline().addLast(new  HttpServerHandler()); 
                        } 
                    }); 
             // 绑定端口,启动服务器             ChannelFuture future = bootstrap.bind(PORT).sync();  
            System.out.println("HTTP  服务器已启动,监听端口:" + PORT); 
             // 等待服务器关闭             future.channel().closeFuture().sync();  
        } finally { 
            // 关闭 EventLoopGroup             bossGroup.shutdownGracefully();  
            workerGroup.shutdownGracefully();  
        } 
    } 
}


标签: #Netty核心原理 #HTTP服务器