Netty Reator(二)Scalable IO in Java

Netty 系列目录 (https://www.cnblogs.com/binarylei/p/10117436.html)

相关文章:

Doug Lea 大神的《Scalable IO in Java》http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf:可伸缩的 IO 模型

大部分 IO 都是下面这个步骤,

  • Read request
  • Decode request
  • Process service
  • Encode reply
  • Send reply

一、经典的网络 IO 模型

传统的 IO 模型是一个 socket 一个线程,代码如下:

class Server implements Runnable {
public void run() {
try {
ServerSocket ss = new ServerSocket(PORT);
while (!Thread.interrupted())
new Thread(new Handler(ss.accept())).start(); //创建新线程来handle
// or, single-threaded, or a thread pool
} catch (IOException ex) { /* ... */ }
} static class Handler implements Runnable {
final Socket socket;
Handler(Socket s) { socket = s; }
public void run() {
try {
byte[] input = new byte[MAX_INPUT];
socket.getInputStream().read(input);
byte[] output = process(input);
socket.getOutputStream().write(output);
} catch (IOException ex) { /* ... */ }
}
private byte[] process(byte[] cmd) { /* ... */ }
}
}

显然简单的多线程会带来扩展性问题,当 client 数量变的很多的时候,还其他的可用性、性能的问题。解决方法就是 Divide-and-conquer,分开后,就需要 Event-driven Designs 来串联起来...

二、单线程( BasicReactor Design)

所有事情 read、process、write 都由单个线程完成,完成一步重新设置下一步的 event。问题当然就是,其中任何步骤阻塞其它任务就阻塞了,因为只有一个线程。

class Reactor implements Runnable {
final Selector selector;
final ServerSocketChannel serverSocket; Reactor(int port) throws IOException { // Reactor 初始化
selector = Selector.open();
serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(port));
serverSocket.configureBlocking(false); // 非阻塞
SelectionKey sk = serverSocket.register(selector, SelectionKey.OP_ACCEPT); // 分步处理,第一步,接收accept事件
sk.attach(new Acceptor()); //attach callback object, Acceptor
} public void run() {
try {
while (!Thread.interrupted()) {
selector.select();
Set selected = selector.selectedKeys();
Iterator it = selected.iterator();
while (it.hasNext())
dispatch((SelectionKey)(it.next()); //Reactor负责dispatch收到的事件
selected.clear();
}
} catch (IOException ex) { /* ... */ }
} void dispatch(SelectionKey k) {
Runnable r = (Runnable)(k.attachment()); //调用之前注册的callback对象
if (r != null)
r.run();
} class Acceptor implements Runnable { // inner
public void run() {
try {
SocketChannel c = serverSocket.accept();
if (c != null)
new Handler(selector, c);
}
catch(IOException ex) { /* ... */ }
}
}
} final class Handler implements Runnable {
final SocketChannel socket;
final SelectionKey sk;
ByteBuffer input = ByteBuffer.allocate(MAXIN);
ByteBuffer output = ByteBuffer.allocate(MAXOUT);
static final int READING = 0, SENDING = 1;
int state = READING; Handler(Selector sel, SocketChannel c) throws IOException {
socket = c; c.configureBlocking(false);
// Optionally try first read now
sk = socket.register(sel, 0);
sk.attach(this); //将Handler作为callback对象
sk.interestOps(SelectionKey.OP_READ); //第二步,接收Read事件
sel.wakeup();
}
boolean inputIsComplete() { /* ... */ }
boolean outputIsComplete() { /* ... */ }
void process() { /* ... */ } public void run() {
try {
if (state == READING) read();
else if (state == SENDING) send();
} catch (IOException ex) { /* ... */ }
} void read() throws IOException {
socket.read(input);
if (inputIsComplete()) {
process();
state = SENDING;
// Normally also do first write now
sk.interestOps(SelectionKey.OP_WRITE); //第三步,接收write事件
}
}
void send() throws IOException {
socket.write(output);
if (outputIsComplete()) sk.cancel(); //write完就结束了, 关闭select key
}
} //上面 的实现用Handler来同时处理Read和Write事件, 所以里面出现状态判断
//我们可以用State-Object pattern来更优雅的实现
class Handler { // ...
public void run() { // initial state is reader
socket.read(input);
if (inputIsComplete()) {
process();
sk.attach(new Sender()); //状态迁移, Read后变成write, 用Sender作为新的callback对象
sk.interest(SelectionKey.OP_WRITE);
sk.selector().wakeup();
}
}
class Sender implements Runnable {
public void run(){ // ...
socket.write(output);
if (outputIsComplete()) sk.cancel();
}
}
}

单线程模式的局限还是比较明显的。所以改进是将比较耗时的部分,从 reactor 线程中分离出去,让 reactor 专门负责 IO,而另外创建 Thread Pool 和 queue 来缓存和处理任务。所以其实已经进化成 Proactor 模式,异步模式。

三、多线程(Worker Threads)

class Handler implements Runnable {
// uses util.concurrent thread pool
static PooledExecutor pool = new PooledExecutor(...);
static final int PROCESSING = 3;
// ...
synchronized void read() { // ...
socket.read(input);
if (inputIsComplete()) {
state = PROCESSING;
pool.execute(new Processer()); //使用线程pool异步执行
}
} synchronized void processAndHandOff() {
process();
state = SENDING; // or rebind attachment
sk.interest(SelectionKey.OP_WRITE); //process完,开始等待write事件
} class Processer implements Runnable {
public void run() { processAndHandOff(); }
}
}

使用多个 reactor 进程,主 reactor 只负责 accept,然后将接收到的 socketchannel 交给 Thread Pool 去处理。

四、主从(Multiple Reactor Threads)

Selector[] selectors; // 一个 selector 代表一个 subReactor
int next = 0;
class Acceptor { // ...
public synchronized void run() { ...
Socket connection = serverSocket.accept(); // 主 selector 负责 accept
if (connection != null)
new Handler(selectors[next], connection); //选个 subReactor 去负责接收到的 connection
if (++next == selectors.length) next = 0;
}
}

每天用心记录一点点。内容也许不重要,但习惯很重要!

Netty Reator(二)Scalable IO in Java的更多相关文章

  1. 【精尽Netty源码解析】1.Scalable IO in Java——多Reactor的代码实现

    Java高伸缩性IO处理 在Doug Lea大神的经典NIO框架文章<Scalable IO in Java>中,具体阐述了如何把Reactor模式和Java NIO整合起来,一步步理论结 ...

  2. 《Scalable IO in Java》译文

    <Scalable IO in Java> 是java.util.concurrent包的作者,大师Doug Lea关于分析与构建可伸缩的高性能IO服务的一篇经典文章,在文章中Doug L ...

  3. 一文弄懂-《Scalable IO In Java》

    目录 一. <Scalable IO In Java> 是什么? 二. IO架构的演变历程 1. Classic Service Designs 经典服务模型 2. Event-drive ...

  4. 学习 Doug Lea 大神写的——Scalable IO in Java

    学习 Doug Lea 大神写的--Scalable IO in Java 网络服务 Web services.分布式对象等等都具有相同的处理结构 Read request Decode reques ...

  5. 《Scalable IO in Java》笔记

    Scalable IO in Java http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf 基本上所有的网络处理程序都有以下基本的处理过程:Read reque ...

  6. Scalable IO in Java

    Scalable IO in Java http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf 大部分IO都是下面这个步骤, Most have same basi ...

  7. Scalable IO in Java【java高效IO】

    第一次翻译,如有错误,请指正 1.Outline 大纲Scalable network services  高效网络服务 Event-driven processing  事件驱动处理 Reactor ...

  8. Java基础(十二)IO输入输出

    一.IO 概述 1.IO 概念 IO:I 代表 Input 输入:O 代表 Output 输出. Java 中 IO 是以流为基础进行输入输出,所有的数据被串行化(保存)写入输出流,或者从输入流读入. ...

  9. NetCore Netty 框架 BT.Netty.RPC 系列随讲 二 WHO AM I 之 NETTY/NETTY 与 网络通讯 IO 模型之关系?

    一:NETTY 是什么? Netty 是什么?  这个问题其实百度上一搜一堆. 这是官方话的描述:Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个 ...

随机推荐

  1. 八、AbstractFactory 抽象工厂模式

    设计原理: 代码清单: 抽象 Factory : public abstract class Factory { public static Factory getFactory(String cla ...

  2. SOA 是什么

    SOA 英文:Service-Oriented Architecture,面向服务的架构. 是一种面向通用集成服务的.松耦合的架构实现方式,是web时代服务发展的产物: 使用"分层" ...

  3. 基于.net开发chrome核心浏览器【一】(转)

    http://www.cnblogs.com/liulun/archive/2013/03/18/2874276.html 说明: 这是本系列的第一篇文章,我会尽快发后续的文章. 源起 1.加快葬送I ...

  4. idea使用maven打包jar包

    1.在pom.xml中加入以下内容: <?xml version="1.0" encoding="UTF-8"?> <project xmln ...

  5. 网站访问者UA检测及跳转

    /*!* UA检测及跳转*/;(function(){ var whatdevice = {}; var myUA = window.navigator.userAgent.toLowerCase() ...

  6. leetcode 字符串类型题

    1,Vaild Palindrome bool isPalindrome(string& s) { transform(s.begin(), s.end(), s.begin(), tolow ...

  7. redismyadmin安装(支持redis4 集群模式)

    yum install php-pecl-redis https://github.com/daivem/RedisMyAdmin下载最新的安装包,解压yum install nginx php ph ...

  8. npm、webpack、vue-cli快速上手版

    node.js和npm npm的安装和更新 Node.js下载安装,npm自带的包管理工具. 查看安装版本信息: node -v 查看node.js版本信息 npm -v 查看npm版本信息 更新np ...

  9. Django具体操作(五)

    一.中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影 ...

  10. python中if not x: 和 if x is not None: 和 if not x is None的使用和区别

    代码中经常会有变量是否为None的判断,有三种主要的写法: 第一种是`if x is None`: 第二种是 `if not x:`: 第三种是`if not x is None`(这句这样理解更清晰 ...