X Tutup
Skip to content

Latest commit

 

History

History
executable file
·
137 lines (76 loc) · 8.51 KB

File metadata and controls

executable file
·
137 lines (76 loc) · 8.51 KB

从 BIO、NIO、AIO 到 Netty 再到 Spring WebFlux:演进与应用

IO模型说起,貌似工作中很少使用IO,更别提NIO,但实际上我们工作中每天都在和IO打交道。我们所用到的中间件redis,rocketMq,nacos,mse,dubbo等等存在文件操作,存在网络通信的地方就存在IO。所以深入了解IO模型重要性可想而知,IO操作作为计算机系统中一个基本操作,几乎所有应用程序都需要,了解不同IO模型可助我们理解应用程序中IO操作底层原理,从而更好地优化应用程序的性能和可靠性。

IO 分类

1.BIO(Blocking I/O):同步阻塞I/O,传统的I/O模型。在进行I/O操作时,必须等待数据读取或写入完成后才能进行下一步操作。

2.NIO(Non-blocking I/O):同步非阻塞I/O,是一种事件驱动的I/O模型。在进行I/O操作时,不需要等待操作完成,可以进行其他操作。

3.AIO(Asynchronous I/O):异步非阻塞I/O,是一种更高级别的I/O模型。在进行I/O操作时,不需要等待操作完成,就可继续进行其他操作,当操作完成后会自动回调通知

从 BIO、NIO、AIO 多路复用 到 Netty 再到 Spring WebFlux 的演进与应用

引言

在现代高并发应用中,服务器的并发能力决定了系统的响应速度和处理性能。传统的阻塞式I/O (BIO) 模型已经无法满足高并发场景下的需求,随着技术的进步,NIO(非阻塞I/O)、AIO(异步I/O)等技术逐步发展并广泛应用。近年来,基于多路复用机制的高性能框架如 Netty 以及响应式编程框架 Spring WebFlux 的兴起,为现代 Web 开发提供了新的思路和技术手段。本文将全面梳理从 BIO、NIO 到 AIO,再到 Netty、Spring WebFlux 的技术演进,深入探讨其工作原理、应用场景和优缺点。

一、阻塞式I/O (BIO)

1.1 BIO 模型介绍

BIO (Blocking I/O) 是最基础的 I/O 模型,在 BIO 模型中,服务器与每个客户端之间的连接是通过阻塞的 socket 方式来进行的。每一个连接都会占用一个线程,服务器在接收到客户端请求时,会创建一个新的线程来处理该请求。如果有大量的客户端连接请求,服务器需要创建大量线程来处理,从而增加了线程上下文切换的开销。

1.2 BIO 工作流程

  1. 服务器端启动监听某个端口,等待客户端连接。
  2. 每个客户端连接后,服务器会为其分配一个线程专门处理这个连接上的 I/O 操作。
  3. 客户端发送请求,服务器处理并返回结果。
  4. 如果没有连接进来,线程会一直阻塞在 accept() 函数处。

1.3 BIO 的缺点

BIO 模型虽然简单易用,但由于其阻塞的特性,使得它在高并发场景下效率低下,面临着以下几个问题:

  • 线程资源消耗大:每个客户端连接都会占用一个线程,线程过多会导致上下文切换的开销增加,性能下降。
  • 并发能力有限:当连接数剧增时,线程资源会被耗尽,从而导致服务器响应速度下降,甚至宕机。
  • 可扩展性差:由于每个连接都需要占用一个独立的线程,因此无法轻易扩展到大规模并发的应用场景中。

二、非阻塞 I/O (NIO)

2.1 NIO 概念与模型

为了克服 BIO 模型在高并发场景下的不足,JDK 在 1.4 版本中引入了 NIO(Non-blocking I/O)模型。NIO 是一种非阻塞的 I/O 模型,它通过通道(Channel)和缓冲区(Buffer)来进行数据的读写,并结合多路复用器(Selector)来实现单线程处理多连接的机制,从而提升了系统的并发能力。

2.2 NIO 的核心组件

  1. Channel:通道类似于传统的流(Stream),但与流不同的是,通道是双向的,可以同时进行读和写操作。常见的通道包括 FileChannelSocketChannelServerSocketChannel 等。
  2. Buffer:缓冲区是 NIO 中用于数据存储的容器。所有数据都必须通过缓冲区来进行读写。常见的缓冲区有 ByteBufferCharBuffer 等。
  3. Selector:多路复用器是 NIO 中实现单线程处理多个连接的关键组件。通过 Selector,应用程序可以同时监听多个通道上的事件,如连接就绪、读写就绪等,而不必为每个连接创建独立的线程。

2.3 NIO 工作流程

  1. 创建 ServerSocketChannel 并设置为非阻塞模式。
  2. 创建 Selector,并将 ServerSocketChannel 注册到 Selector 上。
  3. 通过 select() 方法轮询所有注册的通道,监听就绪的事件。
  4. 当有 I/O 事件就绪时,取出对应的通道进行处理。

2.4 NIO 的优点

  • 资源利用率高:通过多路复用技术,一个线程可以处理多个连接,避免了 BIO 中每个连接占用一个线程的情况。
  • 非阻塞操作:I/O 操作不会阻塞线程,线程可以处理其他任务,从而提高了吞吐量。
  • 高并发场景性能优越:由于线程数量不再与连接数成正比,NIO 能够在高并发场景下保持较高的性能。

2.5 NIO 的缺点

  • 编程复杂度高:NIO 需要开发者自己处理通道的读写、缓冲区的管理和事件的分发,代码相较于 BIO 复杂很多。
  • 性能瓶颈:虽然 NIO 模型相比 BIO 提升了性能,但在某些情况下,轮询操作的效率可能不够高。

三、异步 I/O (AIO)

3.1 AIO 模型介绍

AIO (Asynchronous I/O) 模型,也称为 NIO.2,是在 JDK 7 中引入的一种新的 I/O 模型。与 NIO 的非阻塞操作不同,AIO 采用了真正的异步 I/O 操作。开发者无需手动处理 I/O 事件的轮询和回调,而是将 I/O 操作委托给操作系统,操作系统在 I/O 操作完成后通知应用程序。

3.2 AIO 的工作机制

  1. 应用程序发起一个异步 I/O 请求,并立即返回,继续处理其他任务。
  2. 操作系统后台处理 I/O 操作。
  3. I/O 操作完成后,操作系统通过回调函数通知应用程序。

3.3 AIO 的优点

  • 真正的异步操作:开发者无需手动处理轮询,操作系统完成 I/O 操作后会自动通知应用程序。
  • 高效的资源利用:AIO 能够充分利用系统资源,特别是在高并发、大量 I/O 操作的场景下。

3.4 AIO 的缺点

  • 平台依赖性:AIO 的实现依赖于操作系统的底层异步 I/O 支持,某些操作系统可能对 AIO 的支持并不完善。

四、Netty

4.1 Netty 简介

Netty 是一个基于 NIO 的高性能网络框架,封装了 Java NIO 的复杂性,提供了更友好的 API 来处理网络编程,特别适用于高并发和大规模应用场景。Netty 支持多种协议(如 HTTP、WebSocket、TCP),并能够很好地处理复杂的网络通信需求。

4.2 Netty 的核心组件

  1. Channel:Netty 中的 Channel 表示一个网络连接,类似于 NIO 中的 SocketChannel
  2. EventLoop:Netty 中的事件循环,负责处理通道中的 I/O 操作。每个 EventLoop 可以处理多个通道。
  3. ChannelPipeline 和 ChannelHandlerChannelPipeline 是一个处理网络事件的责任链,而 ChannelHandler 则是负责处理实际的 I/O 事件(如读、写、连接等)。

4.3 Netty 的优点

  • 高性能:Netty 底层使用 NIO,并对其进行了进一步的优化,在高并发场景下表现优越。
  • API 简单:Netty 屏蔽了底层复杂的 NIO 细节,提供了更高层次的 API,使得开发者能够专注于业务逻辑。
  • 多协议支持:Netty 支持多种网络协议,具有良好的扩展性。

4.4 Netty 的应用场景

  • 分布式系统中的 RPC 通信。
  • 高并发 WebSocket 服务。
  • 游戏服务器、大数据传输等。

五、Spring WebFlux

5.1 Spring WebFlux 简介

Spring WebFlux 是 Spring 5 引入的一个响应式非阻塞 Web 框架,旨在解决传统 Spring MVC 在高并发场景下性能瓶颈问题。WebFlux 基于 Reactor 库实现,采用了响应式流(Reactive Streams)标准,并支持异步非阻塞的编程模型。

5.2 Spring WebFlux 的特性

  1. 非阻塞 I/O:WebFlux 采用 Reactor 异步非阻塞框架,能够高效处理大量并发请求。
  2. 响应式编程:通过 MonoFlux 两种响应式类型,WebFlux 支持对流式数据进行处理。
  3. 容器支持:WebFlux 支持多种异步容器,如 Netty、Undertow 和 Servlet 3.1+ 容器。
X Tutup