java io模型浅谈(老司机带你装逼带你飞)

java io模型浅谈(老司机带你装逼带你飞)

作为一个应用程序,除了单机版演示程序外,基本上都需要与外部进行通讯。如文件读写,mysql,redis,mq等第三方数据存储通讯。而应用系统内组件间的通信就需要自定义协议进行数据交换,常见的应用层如http、socket都涉及到io模型机制。

java io模型浅谈(老司机带你装逼带你飞)

网上大把的讲解boi和nio原理的文章,下面主要根据Doug Lea 大神在State University of New York at Oswego 教程结合自己的个人理解进行java io的设计思路的分析,有疑问的地方大家可以拿出来讨论。

对于一个后台服务程或者中间库组件,大部分有如下的基础处理逻辑:

  1. Read Request 读取请求内容

  2. Decode Request 解码请求内容

  3. Process Service 业务逻辑处理

  4. Encode Response 编码应答消息

  5. Send Response 发送请求应答

因业务逻辑不同,应用程序在上面每个步骤所进行的处理不同,比如读取请求内容,就有json、xml、二进制等内容格式。 Decode Request就是根据具体的协议进行解码。

基于上面的处理步骤,常见的io模型有如下几种:

BIO(典型IO模型)

java io模型浅谈(老司机带你装逼带你飞)

每个request开启一个线程,处理上面所有的步骤。下面简单伪代码说明

server接受client请求

java io模型浅谈(老司机带你装逼带你飞)

每个请求启动一个线程进行处理(这里可以使用线程池)

java io模型浅谈(老司机带你装逼带你飞)

优点:编码简单,业务逻辑清晰。 适用于业务量不大情景;

缺点:每个client request一个线程进行处理,业务量持续增长,过多线程会增加程序内存,且频繁线程切换,会增加业务处理时间。即使采用线程池,线程池无空闲线程时,多余请求就会处理等待状态,无法及时应答客户端。同时,无法做到平滑扩容。

NIO(异步IO模型)

异步io的思想就是分而治之,我们可以这样来理解,上面的所有步骤(read request、decode request 、handler server、encode response 、send response)分成不同的非阻塞事件(可以类似button click event),并给上面的所有事件添加handler回调处理(类似 click listener)。当事件被触发时候(button be clicked),执行响应的handler事件。

button 异步事件驱动

java io模型浅谈(老司机带你装逼带你飞)

当然 异步io只是类似上面的思想,具体的实现和设计有一定区别,大家可以通过熟悉的button事件来进行理解。

优点:

  1. 更少的资源,不需要每个client一个线程进行处理;

  2. 不需要频繁的线程间调度,更少的锁操作

    缺点:

  1. 编程难度增加,一个完整的逻辑被切分成不同事件进行处理

  2. 所有的事件分发通过一个线程进行,有一定成都的延时

NIO(reactor 单线程模型)

单线程reactor模型,直接上图类比

java io模型浅谈(老司机带你装逼带你飞)

参照上图的button 点击事件类比:

  1. Ractor模块负责将io事件分发到对应的handler,类似button 中awt thread;

  2. acceptor、read、send 负责io事件的处理,类似awt ActionListeners;

  3. io事件的绑定和handler绑定,类似act addActionListeners;

  4. IO事件在这里包括socket的连接和断开,数据的读写。其中acceptor负责处理socket连接事件,read 负责数据读,send负责数据写;

  5. 这里的实现需要java nio的支持,包括 channles、buffers、Selectors、SelectionKeys;

下面就按照上面的总体思想,用java nio 来实现reactor模型。

reactor io事件分发模块

java io模型浅谈(老司机带你装逼带你飞)

acceptor事件处理(client connect)

java io模型浅谈(老司机带你装逼带你飞)

Read Write io事件NioHandler处理(这里展示client连接上了,就发送ping ,server收到会用pong)

向selector注册read 事件

java io模型浅谈(老司机带你装逼带你飞)

selector 当read准备好后,会通过reactor的将read事件 分发到此handler(reactor代码的dispatch方法),这里将读写事件在同一个handler中进行处理。

java io模型浅谈(老司机带你装逼带你飞)

以上为简单的nio reactor模型的实现,大家可以对照button click 流程进行理解。

NIO(reactor 多线程模型)

在上面的单线程reactor模型中,所有io事件处理都是一个线程中进行,对于一些小容量应用场景,可以使用单线程模型。但是对于高负载、大并发的应用场景却不合适。

work Thread 线程池:reactor只负责分发io事件,事件处理由work Thread处理。下图可以看到,hander收到读写事件后,先可以放入一个queue中,保证io 线程的处理效率,在通过一个thread pool,来消费task queue中的事件。

java io模型浅谈(老司机带你装逼带你飞)

多reacotr 线程:上面的方案中,reactor io线程还是只有一个,对于高负载、大并发的应用场景仍会无法满足。

java io模型浅谈(老司机带你装逼带你飞)

可以直接在acceptor中对于不同的client 连接注册到到对应的selector中,这样每个连接上上来的client可以注册到对应的selector中,使用对应的io thread 来处理io事件:

java io模型浅谈(老司机带你装逼带你飞)

本篇文章主要从设计思路上面介绍nio reactor原理,大名鼎鼎的netty框架其实也是按照reacotr模型进行设计,大家在了解reactor模型的基础上,可以看下netty的原理,有时间可以和大家分享下,可以达到更好的效果。


分享到:


相關文章: