Doug Lea 在 Scalable IO in Java 的 PPT 中描述了 Reactor 编程模型的思想,大部分 NIO 框架和一些中间件的 NIO 编程都与它一样或是它的变体。本文结合 PPT 按照自己的理解整理而来,最终编写了一个简单的 NIO 回显服务。

Reactor 之所以高效是因为采用了分而治之事件驱动的设计。大部分网络服务像 Web 服务器、分布式对象的通信等大多数具有相同的基本处理流程:

  • 读取请求数据 - read
  • 按协议解析请求 - decode
  • 业务处理 - process
  • 按协议编码内容生成响应 - encode
  • 发送响应 - send

传统的服务器设计是:一连接一处理线程,也就是我们常说的 BIO 编程。BIO 在读取和发送时是阻塞的,在请求的整个生命周期内,不管有没有数据可读或待发送,都绑定和占用了这个处理线程。

传统模型中,线程的处理单元是一次完整的请求,为了把线程解放出来,Reactor 对这个处理单元进行了分解。

1. 分而治之

Reactor 模式将处理过程分为多个小任务,每个任务执行一个非阻塞的操作,任务通常由一个 IO 事件触发执行。这种机制在 java.nio 中提供了支持:

  • 非阻塞的读和写
  • 调度与发生的 IO 事件关联的任务

BIO 线程是以 read->decode->process->encode->send 的顺序串行处理,NIO 将其分成了三个执行单元:读取、业务处理和发送,处理过程如下:

  • 读取:如果无数据可读,线程返回线程池;发生读IO事件,申请一个线程处理读取,读取结束后处理业务
  • 业务处理:线程同步处理完业务后,生成响应内容并编码,返回线程池
  • 发送:发生写IO事件,申请一个线程进行发送

可以看出一个明显的区别就是,一次请求的处理过程是由多个不同的线程完成的,感觉和指令的串行执行并行执行有点类似。

分而治之的关键在于非阻塞,这样就能充分利用线程,压榨 CPU,提高系统的吞吐能力。

2. 事件驱动

通常比其他模型更高效,它使用的资源更少,不用针对每个请求启用一条线程,减少了上下文切换,减少阻塞。但任务调度可能会慢,必须手动将事件和处理动作绑定。

通常编程比较困难,它必须为服务设计多个逻辑状态,以便跟踪和中断恢复,这也是在非阻塞编程中有大量状态机运用的原因。

NIO 中总共设计了 4 种事件,每个事件发生都会调度关联的任务,分别是:

  • OP_ACCEPT: 服务端监听到了一个连接,准备接收
  • OP_CONNECT: 客户端与服务器连接建立成功
  • OP_READ: 读事件就绪,通道有数据可读
  • OP_WRITE: 写事件就绪,可以向通道写入数据

java.nio 对事件驱动也提供了支持:

  • Channels: 连接到文件、Socket 等,支持非阻塞读取
  • Buffers: 类似数组的对象,可由通道直接读取或写入
  • Selectors: 通知哪组通道有 IO 事件
  • SelectionKeys: 维护 IO 事件的状态和绑定信息

3. Reactor 模式

Reactor 是一种设计模式,wikipedia 对其定义如下:

Reactor 是一个或多个输入事件的处理模式,用于处理并发传递给服务处理程序的服务请求。服务处理程序判断传入请求发生的事件,并将它们同步的分派给关联的请求处理程序。

Reactor 模式按照职责不同,通常可以把线程分为 Reactor 线程、IO 线程和业务线程:

  • Reactor 线程:轮询通知发生IO的通道,并分派合适的 Handler 处理
  • IO 线程:执行实际的读写操作
  • 业务线程:执行应用程序的业务逻辑

PPT 中介绍了三种版本的实现。

3.1 单线程版本

单线程版本就是用一个线程完成事件的通知、实际的 I/O 操作和业务处理。Reactor 作用就是要迅速的触发 Handler ,显然 Handler 处理的过程会导致 Reactor 变慢,此时可以将 非 IO 操作从 Reactor 线程中分离。

3.2 多线程版本

多线程版本将业务处理和 I/O 操作进行分离,Reactor 线程只关注事件分发和实际的 IO 操作,业务处理如协议的编解码都分配给线程池处理。可能会有这样的情况发生,业务处理很快,大部分的 Reactor 线程都在处理 IO,导致 CPU 闲置,降低了响应速度。

3.3 主从 Reactor 版本

主从 Reactor 版本设计了一个 主Reactor 用于处理连接接收事件,多个 从Reactor 处理实际的 I/O,分工合作,匹配 CPU 和 IO 速率。

3.4 一个变体

以上的三个版本中,Reactor 线程都参与了 IO 操作,有一种变体是把实际的 IO 操作也转移到线程池线程中,这样从数据的读取到业务的处理都是由一个线程完成,可以避免锁的竞争。

小结

知易行难,为了更好的理解,这里对 PPT 中介绍的3个版本实现了一个简单的回显服务,内部有比较详细的代码注释。

源码地址https://github.com/tonwu/reactor

Reactor 典型的 NIO 编程模型的更多相关文章

  1. Nio编程模型总结

    终于,这两天的考试熬过去了, 兴致冲冲的来整理笔记来, 这篇博客是我近几天的NIO印象笔记汇总,记录了对Selector及Selector的重要参数的理解,对Channel的理解,常见的Channel ...

  2. NIO 编程模型

    NIO 编程模型 Doug Lea 在 Scalable IO in Java 的 PPT 中描述了 Reactor 编程模型的思想,大部分 NIO 框架和一些中间件的 NIO 编程都与它一样或是它的 ...

  3. 手动搭建I/O网络通信框架3:NIO编程模型,升级改造聊天室

    第一章:手动搭建I/O网络通信框架1:Socket和ServerSocket入门实战,实现单聊 第二章:手动搭建I/O网络通信框架2:BIO编程模型实现群聊 在第二章中用BIO编程模型,简单的实现了一 ...

  4. Java网络编程和NIO详解3:IO模型与Java网络编程模型

    Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...

  5. 谈谈传统BIO网络编程模型的局限性与NIO

    先来看看我们的server端: 创建一个serversocket,进行监听,每来一个客户端,就启动一个新启动为其服务: private void createListenSocket() { //如果 ...

  6. NIO&AIO编程模型

    NIO线程模型 什么是NIO线程模型? 上图是NIO的线程模型,  基于select实现,   这种线程模型的特点:  多条channel通过一个选择器和单挑线程绑定, 并且在这种编程模型中, Cha ...

  7. Linux IO模型和网络编程模型

    术语概念描述: IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者. 阻塞和非阻塞,是函数/方法的实现方式,即在数据就绪之前是立刻返回还是等待. 以文件IO为例,一个IO读过程是文件 ...

  8. 手动搭建I/O网络通信框架4:AIO编程模型,聊天室终极改造

    第一章:手动搭建I/O网络通信框架1:Socket和ServerSocket入门实战,实现单聊 第二章:手动搭建I/O网络通信框架2:BIO编程模型实现群聊 第三章:手动搭建I/O网络通信框架3:NI ...

  9. Reactor 模型(一)基本并发编程模型

    Reactor 模型(一)基本并发编程模型 Netty 系列目录 (https://www.cnblogs.com/binarylei/p/10117436.html) 在讲解 Reactor 线程模 ...

随机推荐

  1. BZOJ_1408_[Noi2002]Robot_数学

    Description Input Output Sample Input 3 2 1 3 2 5 1 Sample Output 8 6 75 HINT 90号机器人有10个老师,加上它自己共11个 ...

  2. BZOJ_5301_[Cqoi2018]异或序列&&CF617E_莫队

    Description 已知一个长度为 n 的整数数列 a[1],a[2],…,a[n] ,给定查询参数 l.r ,问在 [l,r] 区间内,有多少连续子 序列满足异或和等于 k . 也就是说,对于所 ...

  3. [转]现代Linux系统上的栈溢出攻击

    1. 基本内容 这个教程试着向读者展示最基本的栈溢出攻击和现代Linux发行版中针对这种攻击的防御机制.为此我选择了最新版本的Ubuntu系统(12.10),因为它默认集成了几个安全防御机制,而且它也 ...

  4. postman-----使用CSV和Json文件实现批量接口测试

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px ".PingFang SC"; color: #454545 } span ...

  5. Postman----支持markdown可自动生成接口文档

    1.postman支持markdown作为集合中的请求,对集合和文件夹进行文字描述的方式,您可以嵌入屏幕截图和其他图像已获得更多描述性的介绍. 2.已markdown语法为准,填写自己想要展示的内容 ...

  6. 利用策略模式优化过多 if else 代码

    前言 不出意外,这应该是年前最后一次分享,本次来一点实际开发中会用到的小技巧. 比如平时大家是否都会写类似这样的代码: if(a){ //dosomething }else if(b){ //dosh ...

  7. 游戏AI之路径规划(3)

    目录 使用路径点(Way Point)作为节点 洪水填充算法创建路径点 使用导航网(Navigation Mesh)作为节点 区域分割 预计算 路径查询表 路径成本查询表 寻路的改进 平均帧运算 路径 ...

  8. SSM框架视频资料

    SSM框架视频资料 进行过 Java Web 项目开发的同学,可能都知道 SSM 框架,即 Spring + SpringMVC + Mybatis .很多项目的主体框架都是采用这种模式,这也是 Ja ...

  9. 45个值得收藏的 CSS 形状

    摘要: CSS炫技. 原文:45个值得收藏的 CSS 形状 作者:前端小智 Fundebug经授权转载,版权归原作者所有. CSS能够生成各种形状.正方形和矩形很容易,因为它们是 web 的自然形状. ...

  10. android:layout_weight属性详解

    weight:重量.权重. 当我们给一个view设置了android:layout_weight属性,意味着赋予它话语权,常规思维就是谁的weight大,谁说了算(空间占比大). 下面我们来看下具体的 ...