本文参考Doug Lea的Scalable IO in Java.

网络服务

随着网络服务的越来越多,我们对网络服务的性能有了更高的要求,提供一个高性能,稳定的web服务是一件很麻烦的事情,所以有了netty框架帮我们完成。

我们对各种各样的网络服务进行抽象,得到最基本的业务流程:

1:读取请求信息

2:对请求信息进行解码

3:进行相关的业务处理

4:对处理结果进行编码

5:发送请求

看到这,netty的ChannelHandler就是干这几件事情的。

传统的网络服务

在jdk1.4之前,我们只有BIO,所以当时的网络服务的架构是这样的。

每个线程处理一个请求, 由于线程个数和cpu个数的原因,这种设计性能是有上限的,所以就有了集群模式:tomcat集群。

/**
* Created by gaoxing on 2015-01-20 .
*/
public class ClasssicServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket=new ServerSocket(8888,10);
System.out.println("server is start");
while( ! Thread.interrupted())
{
new Thread(new Handler(serverSocket.accept())).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
static class Handler implements Runnable
{
final Socket socket; final static int MAX_SIZE=1024; public Handler(Socket socket)
{
this.socket=socket;
} @Override
public void run() {
//TODO
//在这里对socket中的数据进行读取和处理,然后把结果写入到socket中去
} }
}

高性能的IO目标和Reactor

1:高负载下可以稳定的工作

2:提高资源的利用率

3:低延迟

这有就有了分而治之和事件驱动的思想。这样没有thread就不用瞎跑了,cpu就不用不停的切换Thread . 这样提出了Reactor模式

1:Reactor接收IO事件发送给该事件的处理器处理

2:处理器的操作是非阻塞的。

3:管理事件和处理器的绑定。

这是一个单线程版本,所有的请求都是一个线程处理,当然Reactor不是无缘无故的提出来的,因为jdk提供了nio包,nio使得Reator得于实现

1:channels: 通道就是数据源的抽象,通过它可以无阻塞的读取数据

2:buffers  : 用来装载数据的,可以把从channel读取到buffer中,或者把buffer中的数据写入到channel中

3:selector : 用来监听 有IO事件,并告诉channel

4:selectionkeys:  IO事件和处理器绑定

/**
* Created by gaoxing on 2015-01-20 .
*/
public class Reactor implements Runnable {
final Selector selector ;
final ServerSocketChannel serverSocketChannel; public Reactor(int port) throws IOException {
this.selector=Selector.open();
this.serverSocketChannel=ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(port));
//一定是非阻塞的,阻塞的一个通道就只能处理一个请求了
serverSocketChannel.configureBlocking(false);
//把OP_ACCEPT事件和Acceptor绑定
SelectionKey sk=serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
sk.attach(new Acceptor()); } @Override
public void run() {
while(!Thread.interrupted())
{
try {
selector.select();//该方法是阻塞的,只有IO事件来了才向下执行
Set<SelectionKey> selected=selector.selectedKeys();
Iterator<SelectionKey> it=selected.iterator();
while(it.hasNext())
{
dispatch(it.next());
}
          selected.clear()          
} catch (IOException e) {
e.printStackTrace();
} }
} private void dispatch(SelectionKey next) {
Runnable runnable= (Runnable) next.attachment();
if(runnable!=null)
{
runnable.run();
}
} private class Acceptor implements Runnable{
@Override
public void run() {
SocketChannel channel= null;
try {
channel = serverSocketChannel.accept();
if (channel!=null){
new Handler(selector,channel);
}
} catch (IOException e) {
e.printStackTrace();
} }
}
} class Handler implements Runnable
{
final SelectionKey sk;
final SocketChannel channel;
final static int MAXSIZE=1024;
ByteBuffer input=ByteBuffer.allocate(MAXSIZE);
ByteBuffer output=ByteBuffer.allocate(MAXSIZE); static final int READING=0,SENDING=1;
int state=READING; public Handler(Selector selector,SocketChannel channel) throws IOException {
this.channel=channel; this.channel.configureBlocking(false);
/**
* 这个有个问题,ppt上register是0,
*/
sk=this.channel.register(selector,SelectionKey.OP_READ);
sk.attach(this);
/**
* 这里的作用是,设置key的状态为可读,然后让后selector的selector返回。
* 然后就可以处理OP_READ事件了
*/
sk.interestOps(SelectionKey.OP_READ);
selector.wakeup(); }
@Override
public void run() {
if (state==READING) read();
if (state==SENDING) write();
} void read(){
state=SENDING;
sk.interestOps(SelectionKey.OP_WRITE);
} void write()
{
sk.cancel();
}
}

上面代码注解理解有误:

sk=this.channel.register(selector,0);  这里是初始化一个SelectionKey 不监听事件
sk.interestOps(SelectionKey.OP_READ); 这里设置监听的事件为OP_READ

多线程的Reactor模式

现在的CPU多核的,为了提高对硬件的使用效率需要考虑使用多线程的Reactor设计模式,Reactor主要用来处罚事件的,但是事件的处理会降低Reactor的性能,考虑把事件的处理放到别的线程上来做,有点想android的设计模式,UI线程用来接收用户的事件,事件的处理放到线程去做来提高用户的体验。多线程Reactor有两种一种是Reactor线程只关注io事件,事件处理放到别的线程,一种对事件分类主Reactor只关注Accept事件,子Reactor关注read和write事件。事件处理放到线程去做,这也是netty的设计模式。

class HandlerPool implements  Runnable
{
final SelectionKey sk;
final SocketChannel channel;
final static int MAXSIZE=1024;
ByteBuffer input=ByteBuffer.allocate(MAXSIZE);
ByteBuffer output=ByteBuffer.allocate(MAXSIZE);
static ExecutorService executor = Executors.newFixedThreadPool(100);
static final int READING=0,SENDING=1;
int state=READING; public HandlerPool(Selector selector,SocketChannel channel) throws IOException {
this.channel=channel; this.channel.configureBlocking(false);
/**
* 这个有个问题,这里注册的SelectionKey是不处理的,应该他监听的事件为0
*/
sk=this.channel.register(selector,0);
sk.attach(this);
/**
* 这里的作用是,SelectionKey的监听事件为OP_READ。interestOps对哪个事件感兴趣
*/
sk.interestOps(SelectionKey.OP_READ);
selector.wakeup(); }
@Override
public void run() {
executor.execute(new Processer());
} class Processer implements Runnable
{ @Override
public void run() { }
}
}

这个就在Acceptor里面多实例化几个Selector,它处理Read和Write事件。

大致架构弄懂了。后面边看netty源码,边学习nio

NIO和Reactor的更多相关文章

  1. Java进阶(五)Java I/O模型从BIO到NIO和Reactor模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/java/nio_reactor/ Java I/O模型 同步 vs. 异步 同步I/O 每个请求必须逐个地被处理,一个请 ...

  2. nio的reactor模式

    转自:http://blog.csdn.net/it_man/article/details/38417761 线程状态转换图 就是非阻塞IO 采用多路分发方式举个例子吧,你服务器做一个聊天室,按照以 ...

  3. NIO及Reactor模式

    关于Nio Java NIO即Java Non-blocking IO(Java非阻塞I/O),是Jdk1.4之后增加的一套操作I/O工具包,又被叫做Java New IO. Nio要去解决的问题 N ...

  4. Java进阶知识点:服务端高并发的基石 - NIO与Reactor AIO与Proactor

    一.背景 要提升服务器的并发处理能力,通常有两大方向的思路. 1.系统架构层面.比如负载均衡.多级缓存.单元化部署等等. 2.单节点优化层面.比如修复代码级别的性能Bug.JVM参数调优.IO优化等等 ...

  5. Java进阶知识点5:服务端高并发的基石 - NIO与Reactor模式以及AIO与Proactor模式

    一.背景 要提升服务器的并发处理能力,通常有两大方向的思路. 1.系统架构层面.比如负载均衡.多级缓存.单元化部署等等. 2.单节点优化层面.比如修复代码级别的性能Bug.JVM参数调优.IO优化等等 ...

  6. Java I/O模型从BIO到NIO和Reactor模式(转)

    原创文章,转载请务必将下面这段话置于文章开头处(保留超链接).本文转发自技术世界,原文链接 http://www.jasongj.com/java/nio_reactor/ Java I/O模型 同步 ...

  7. 原生JDK网络编程- NIO之Reactor模式

    “反应”器名字中”反应“的由来: “反应”即“倒置”,“控制逆转”,具体事件处理程序不调用反应器,而向反应器注册一个事件处理器,表示自己对某些事件感兴趣,有时间来了,具体事件处理程序通过事件处理器对某 ...

  8. 网络编程NIO之Reactor线程模型

    目录 单Reactor线程模型 基于工作线程的Reactor线程模型 多Reactor线程模型 多Reactor线程模型示例 结束语 上篇文章中写了一些NIO相关的知识以及简单的NIO实现示例,但是示 ...

  9. 【死磕 NIO】— Reactor 模式就一定意味着高性能吗?

    大家好,我是大明哥,我又来了. 为什么是 Reactor 一般所有的网络服务,一般分为如下几个步骤: 读请求(read request) 读解析(read decode) 处理程序(process s ...

随机推荐

  1. Python3 内置函数补充匿名函数

    Python3 匿名函数 定义一个函数与变量的定义非常相似,对于有名函数,必须通过变量名访问 def func(x,y,z=1): return x+y+z print(func(1,2,3)) 匿名 ...

  2. poj 3083 Children of the Candy Corn 【条件约束dfs搜索 + bfs搜索】【复习搜索题目一定要看这道题目】

    题目地址:http://poj.org/problem?id=3083 Sample Input 2 8 8 ######## #......# #.####.# #.####.# #.####.# ...

  3. 大话设计模式--职责连模式 Chain of Resposibility -- C++实现实例

    1. 职责链模式: 使多个对象都有机会处理请求,从而避免请求发送者和接受者之间的耦合关系,将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它. 当客户提交一个请求时,请求是沿着链传递直 ...

  4. JS字符串转换成数字

    方法主要有三种 转换函数.强制类型转换.利用js变量弱类型转换. 1. 转换函数: js提供了parseInt()和parseFloat()两个转换函数.前者把值转换成整数,后者把值转换成浮点数.只有 ...

  5. linux应用之vim的安装与配置(centos)

    1.vim的安装 #yum search vim   //查看vim相关软件信息 #yum install -y vim*  //在线安装vim 2.vim的配置 (1)~/.viminfo 在vim ...

  6. Convolutional Neural Networks for Visual Recognition 2

    Linear Classification 在上一讲里,我们介绍了图像分类问题以及一个简单的分类模型K-NN模型,我们已经知道K-NN的模型有几个严重的缺陷,第一就是要保存训练集里的所有样本,这个比较 ...

  7. Debian for ARM

    /************************************************************************* * Debian for ARM * 说明: * ...

  8. 省选/NOI刷题Day2

    bzoj2616 放一个车的时候相当于剪掉棋盘的一行,于是就可以转移了,中间状态转移dp套dp,推一下即可 bzoj2878 环套树期望dp 手推一下递推式即可 bzoj3295 树状数组套权值线段树 ...

  9. luogu1901 发射站

    单调栈 正着插一遍反着插一遍 记录每个点左边右边第一个比他高的... yyc太强辣 #include<iostream> #include<cstdlib> #include& ...

  10. ACM学习历程—Hihocoder 1233 Boxes(bfs)(2015北京网赛)

    hihoCoder挑战赛12 时间限制:1000ms 单点时限:1000ms 内存限制:256MB   描述 There is a strange storehouse in PKU. In this ...