Dubbo通信模型的优势——BIO和NIO的区别

摘要:关于BIO和NIO的理解

最近大概看了ZooKeeper和Mina的源码发现都是用Java NIO实现的

一、简介

BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端 有连接请求  时服务器端就  需要启动一个线程  进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。 
NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到 多路复用器 上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。 
AIO(NIO.2):异步非阻塞式IO,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。 

 

1.BIO基本介绍

BIO是传统的Java IO编程,其基本的类和接口在java.io包中
BIO(blocking I/O):同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销

缺点一:IO阻塞

在一次RPC调用开始到完成之前,这个连接一直被此次调用所占用,但是实际上这次调用中,

真正需要网络连接的只有中间的数据传输过程,在客户端写出和服务端读取并执行远端方法这两个时间点,其实网络连接是空闲的。这就是BIO连接中浪费了网络资源的地方。

 

 

 缺点二:大量连接

 

由于BIO的IO阻塞,导致每次RPC调用会占用一个连接。而正因为如此,为了减少频繁创建连接消耗的时间,引入了连接池(此处的连接池指普通的HTTP连接池,非异步连接池)的概念,连接池解决了频繁创建连接的资源消耗,但是没有解决根本性的阻塞问题。而且在服务消费者(客户端)数量远大于服务提供者(服务端)数量的时候,会导致服务提供者建立了大量的连接,而本身由于硬件资源的限制,单机最大连接数是有限的(这个限制以前是1w,也就是以前的C10K问题,据说近几年已经提升至50万个连接),所以在服务消费者过多,而服务提供者数量过少的情况下,服务提供者有因为过多的连接而被拖垮的风险(这需要极大的并发数,每秒上百万次的调用)。当然,要解决这个问题,增加机器,从而增加服务提供者数量是可以解决的,但是没有充分利用单机性能。

 

建立大量连接的另一个弊端,是操作系统频繁的线程上下文切换,因为连接数过多,线程切换频繁,会消耗大量的资源,而且这些切换可能不是必要的。比如当前建立了大量的连接,可能大部分处于阻塞状态,根本没有挨个挨个切换的必要。但是因为操作系统任务调度时并不会忽略阻塞状态的线程,所以造成浪费。

 

 

BIO方式使用于连接数目比较小且固定的架构,这种服务方式对服务器资源要求比价高,并且局限于应用中,JDK1.4以前的唯一选择,程序简单易理解

 

BIO基本模型:

 

 

 

2.NIO基本介绍

NIO全称 java non-blocking IO。从JDK 1.4开始,java提供了一些列改进的输入/输出(I/O)的新特性,被称为NIO,是同步非阻塞的
NIO相关类都被放在java.nio包及其子包下
NIO三大核心部分:Channel(通道),Buffer(缓冲区),Selector(选择器)
NIO是面向缓冲区的,或者面向块编程的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区内前后移动,这就增加了处理过程中的灵活性,使用它可以提供非阻塞的高伸缩性网络
Java NIO的非阻塞模式,使一个线程从某通道发送或者读取数据,但是它仅能得到目前可用的数据,如果目前没有可用的数据时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可读取之前,该线程可以继续做其他事情。非阻塞就是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情

通俗来讲:NIO是可以做到用一个线程处理多个操作的。假设有10000个请求过来,根据实际情况,可以分配50或100个线程来处理。不像BIO一样需要分配10000个线程来处理
NIO基本模型:

 

 

3.NIO单一长连接实现分析

长连接其实不算NIO这里的特点,因为BIO也可以实现长连接(每次写完数据之后手动写入结束符而不关闭流就可以了),而且连接池一般也是使用的长连接方式。

NIO真正解决的是阻塞问题,因为阻塞问题解决了,所以也就不需要大量连接了。

 

 

4.NIO角色示意图

NIO由三种角色组成,Selector、SocketChannel、Buffer。

SocketChannel相当于BIO中的Socket,分为SocketChannel和ServerSocketChannel两种,是真正建立连接并传输数据的管道。这个管道不同于BIO的Socket的点就是,这个管道可以被多个线程共用,线程A使用这个管道写出数据了之后,线程B还可以使用这个管道写出数据,不再被某一次调用所独占。所以就可以不需要像BIO一样建立那么多的连接,一个客户端的一个连接就够了(当然,实际应用中因为机器都是多核,实际上建立核数个连接个人感觉是比较好的)。

Buffer是用来与SocketChannel互通数据的对象,本质上是一块内存区域。SocketChannel是不支持直接读写数据的,所有的读写操作必须通过Buffer来实现。值得一提的是,我们经常说在JVM中有的时候会使用虚拟机之外的内存,说的就是NIO中的Buffer,在分配内存的时候可以选择使用虚拟机外内存,减少数据的复制。

Selector是用来监控SocketChannel的事件的,其实是实现非阻塞的关键。NIO是基于事件的,将BIO中的流式传输改为了事件机制。BIO中,一个连接拥有一个输入/输出流,只要数据传输完成,流就可以读取数据。在NIO中,Selector定义了四种事件,OP_READ、OP_WRITE、OP_CONNECT、OP_ACCEPT。当服务端或者客户端收到写入完成的一次数据时,会触发OP_READ事件,此时可以从连接中读取数据。同理,当可以往连接中写入数据的时候,触发OP_WRITE事件(但是一般情况下这个事件没有必要,因为连接一般都是可写的)。客户端与服务端建立连接的时候,客户端会收到OP_CONNECT事件,而服务端会触发OP_ACCEPT事件。通过这一系列事件将数据的发送与读写解耦,实现异步调用。将一个SocketChannel+一个事件绑定在一个Selector上,Selector本质上是轮询每一个SocketChannel,如果没有事件触发,那么线程阻塞,如果有事件触发,返回对应的SocketChannel,以便进行后续的处理。

使用NIO设计RPC调用分析

前面提到,由于NIO的SocketChannel是非阻塞的,所以不再需要连接池,使用一个连接就够了。

 

 

 

 

5.BIO和NIO的区别

BIO以流的方式处理数据,NIO以块的方式处理数据,块IO的效率比流IO高很多。(比如说流IO他是一个流,你必须时刻去接着他,不然一些流就会丢失造成数据丢失,所以处理这个请求的线程就阻塞了他无法去处理别的请求,他必须时刻盯着这个请求防止数据丢失。而块IO就不一样了,线程可以等他的数据全部写入到缓冲区中形成一个数据块然后再去处理他,在这期间该线程可以去处理其他请求)
BIO是阻塞的,NIO是非阻塞的
BIO基于字节流和字符流进行操作的,而NIO基于Channel(通道)和Buffer(缓冲区)进行操作的,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择器)用于监听多个通道事件,因此使用单个线程就可以监听多个客户端通道

6:NIO异步顺序问题

如上图所示,如果多个线程共用一个连接,那么每个线程调用之后返回的顺序是不可控的,所以有可能先发出数据的反而后得到返回值,这就使得数据对应不上了。个人觉得因为这一点,NIO及其适合聊天室类型的设计,因为每个聊天方都是一个单独的SocketChannel连接,而此时并没有顺序问题。

但是对RPC调用来说,每次调用的返回值必须与调用方对应上,为此,Dubbo的设计是给每个请求设计一个请求id,在发送请求与发送返回值时都带上这个id。详细思路如下图:

7:NIO单一长连接的RPC设计

业务线程在发出请求之前,需要存储一个请求对象,同时挂起相应的业务线程(挂起不会被任务调度,所以不存在线程切换消耗),这个请求对象包含了此次请求的id,然后在获取服务端返回的数据的时候,解析出这个id,通过这个id取出请求对象,并唤醒对应的线程。

 

 

二、各自应用场景 

到这里你也许已经发现,一旦有请求到来(不管是几个同时到还是只有一个到),都会调用对应IO处理函数处理,所以:

(1)NIO适合处理连接数目特别多,但是连接比较短(轻操作)的场景,Jetty,Mina,ZooKeeper等都是基于java nio实现。

(2)BIO方式适用于连接数目比较小且固定的场景,这种方式对服务器资源要求比较高,并发局限于应用中

 

 

具体实现代码可参考:

https://blog.csdn.net/luzhensmart/article/details/106525425

 
posted @   陈晓猛  阅读(240)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示

目录导航