java zookeeper 主从热备_Netty、Redis、ZooKeeper高并发实战(笔记三)

本文介绍了基于Java的Netty、Redis、ZooKeeper在高并发场景下的实战应用,重点讨论了Reactor反应器模式,解释了如何解决传统阻塞式IO的问题,以及如何利用Java NIO实现单线程的反应器模式,通过SelectionKey的attach和attachment方法实现事件分发和处理。
摘要由CSDN通过智能技术生成

Netty、Redis、ZooKeeper高并发实战(笔记三)

将Doug Lea著名的文章《Scalable IO in Java》:http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf,开阔下眼界。

Reactor反应器模式

反应器模式由Reactor反应器线程、Handlers处理器两大角色组成:

(1)Reactor反应器线程的职责:负责响应IO事件,并且分发到Handlers处理器。

(2)Handlers处理器的职责:非阻塞的执行业务处理逻辑。

在Java的OIO编程中,最初和最原始的网络服务器程序,是用一个while循环,不断地监听端口是否有新的连接。如果有,那么就调用一个处理函数来处理,示例代码如下:

while(true){

socket = accept(); //阻塞,接收连接

handle(socket) ;   //读取数据、业务处理、写入结果

}

这种方法的最大问题是:如果前一个网络连接的handle(socket)没有处理完,那么后面的连接请求没法被接收,于是后面的请求通通会被阻塞住,服务器的吞吐量就太低了。对于服务器来说,这是一个严重的问题。

为了解决这个严重的连接阻塞问题,出现了一个极为经典模式:Connection Per Thread(一个线程处理一个连接)模式。

class ConnectionPerThread implements Runnable {

public void run() {

try {

//服务器监听socket

ServerSocketserverSocket =

new ServerSocket(NioDemoConfig.SOCKET_SERVER_PORT);

while (!Thread.interrupted()) {

Socket socket = serverSocket.accept();

//接收一个连接后,为socket连接,新建一个专属的处理器对象

Handler handler = new Handler(socket);

//创建新线程,专门负责一个连接的处理

new Thread(handler).start();

}

} catch (IOException ex) { /* 处理异常 */ }

}

//处理器对象

static class Handler implements Runnable {

final Socket socket;

Handler(Socket s) {

socket = s;

}

public void run() {

while (true) {

try {

byte[] input = new byte[NioDemoConfig.SERVER_BUFFER_SIZE];

/* 读取数据 */

socket.getInputStream().read(input);

/* 处理业务逻辑,获取处理结果*/

byte[] output =null;

/* 写入结果 */

socket.getOutputStream().write(output);

} catch (IOException ex) { /*处理异常*/ }

}

}

}

}

对于每一个新的网络连接都分配给一个线程。每个线程都独自处理自己负责的输入和输出。当然,服务器的监听线程也是独立的,任何的socket连接的输入和输出处理,不会阻塞到后面新socket连接的监听和建立。早期版本的Tomcat服务器,就是这样实现的。

对应于大量的连接,需要耗费大量的线程资源,对线程资源要求太高。在系统中,线程是比较昂贵的系统资源。如果线程数太多,系统无法承受。而且,线程的反复创建、销毁、线程的切换也需要代价。

在反应器模式中,有Reactor反应器和Handler处理器两个重要的组件:

(1)Reactor反应器:负责查询IO事件,当检测到一个IO事件,将其发送给相应的Handler处理器去处理。这里的IO事件,就是NIO中选择器监控的通道IO事件。

(2)Handler处理器:与IO事件(或者选择键)绑定,负责IO事件的处理。完成真正的连接建立、通道的读取、处理业务逻辑、负责将结果写出到通道等。

基于Java NIO,如何实现简单的单线程版本的反应器模式呢?需要用到SelectionKey选择键的几个重要的成员方法:

方法一:void attach(Object o)

此方法可以将任何的Java POJO对象,作为附件添加到SelectionKey实例,相当于附件属性的setter方法。这方法非常重要,因为在单线程版本的反应器模式中,需要将Handler处理器实例,作为附件添加到SelectionKey实例。

方法二:Object attachment()

此方法的作用是取出之前通过attach(Object o)添加到SelectionKey选择键实例的附件,相当于附件属性的getter方法,与attach(Object o)配套使用。

这个方法同样非常重要,当IO事件发生,选择键被select方法选到,可以直接将事件的附件取出,也就是之前绑定的Handler处理器实例,通过该Handler,完成相应的处理。

总之,在反应器模式中,需要进行attach和attachment结合使用:在选择键注册完成之后,调用attach方法,将Handler处理器绑定到选择键;当事件发生时,调用attachment方法,可以从选择键取出Handler处理器,将事件分发到Handler处理器中,完成业务处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值