Hadoop RPC

在介绍Hadoop RPC之前,需要首先介绍一下JAVA NIO,JAVA NIO是jdk发布的全新I/O类库。它不但引入了全新的高效的I/O机制,同时引入了基于Reactor设计模式的多路复用异步模式,NIO的包中主要包含以下几种抽象数据类型。

Channel:NIO把它支持的I/O对象抽象为Channel,它模拟了通信连接,类似于原I/O中的流(Stream),用户可以通过它读取和写入数据。

Buffer:是一块连续的内存区域,一般作为Channel收发数据的载体出现。所有数据都通过Buffer对象来处理,用户永远不会将字节直接写入通道中,相反,需将数据写入包含一个或者多个字节的缓冲区,然后再从缓冲区中读取相应的字节。写的过程也是如此。

Selector:它提供了监控一个或多个通道当前状态的机制,只要Channel向当前Selector中注册了某种特定的事件,Selector就会监听这些事件是否会发生,一旦发生某事件,便会通知对应的Channel。

Channel相关类:

java.nio提供了多种Channel实现,其中,最常用的是以SelectableChannel为基类的通道,SelectableChannel是一种支持阻塞I/O和非阻塞I/O的通道。它存在两个子类,分别是ServerSocketChannel和SocketChannel。

SelectableChannel类的主要方法:

SelectableChannel configureBlocking(boolean block) throws IOException;//设置当前的SelectableChannel的阻塞模式,false非阻塞,true阻塞

SelectionKey register(Selector sel,int ops) throws ClosedChannelException;//将当前的Channel注册到一个Selector中,ops表示注册的事件

ServerSocketChannel类的主要方法:

ServerSocketChannel open() throws IOException;//用于创建ServerSocketChannel的静态工厂方法

SocketChannel accept() throws IOException;//接收来自客户端的连接。

ServerSocket socket();//返回一个与ServerSocketChannel关联的ServerSocket对象,每个ServerSocketChannel对象都有一个ServerSocket对象与之关联

SocketChannel类的主要方法:

open()

socket()

boolean connect(SocketAddress remote) throws IOException;//连接Channel对应的Socket

int read(ByteBuffer dst) throws IOException;//将当前Channel中的数据读取到ByteBuffer中,在阻塞模式下,一直读取数据,直到ByteBuffer满为止;非阻塞模式下,能读多少就读多少,并立即返回结果

int write(ByteBuffer src) throws IOException;//非阻塞模式下,能输出多少数据就输出多少数据,总是立即返回结果;阻塞模式下,尝试将所有数据都读入到src中,然后再返回


Selector类:

static Selector open();//一个静态工厂方法,创建Selector对象

int select(long timeout);//该方法等待并返回发生的事件,一旦某个注册的事件发生,就会返回对应的SelectionKey的数目,否则,一直处于阻塞的状态

set selectKeys()//Selector;//捕获已经发生事件对应的SelectionKey集合

Selector wakeup();//立即唤醒当前处于阻塞状态的Selector


SelectionKey类

Object attach(Object obj);//为当前SelectionKey关联一个Object类型的对象。每个SelectionKey只能关联一个对象

Object attachment();//获取当前SelectionKey关联的对象

SelectableChannel channel();//返回与当前SelectionKey关联的SelectableChannel对象

这里面还定义了几个整形常量,表示4种事件

SelectionKey.OP_ACCEPT;SelectionKey.OP_CONNECT;SelectionKey.OP_READ;SelectionKey.OP_WRITE


下面开始看下Hadoop RPC的源码部分

这个里面主要包含着几个部分,分别是Server,RPC,Client

Server类

在这个类中,还包含几个内部类,分别是Call,Connection,Handler,Listener,Responder

Call类:

这个类主要封装了传递到Server的方法调用信息,包括调用的方法,以及调用方法所需的参数;

id:哪个client调用了Server上的方法

param:封装的方法调用信息

connection:client与Server的连接信息

timestamp:时间标签

response:在Server上调用方法后,需要返回到client的调用结果

public void setResponse(ByteBuffer response);//设定调用方法结果


Listener类

acceptChannel:接收client调用方法信息的管道

selector:负责server的selector

address:绑定的地址

lastCleanupRunTime:清理连接的最后时间

cleanupInterval:清理连接的时间间隔

public Listener() throws IOException;//创建一个ServerSocketChannel非阻塞管道,将其ServerSocketChannel.socket绑定到address上,创建多个Reader,并将ServerSocketChannel注册到Selector中,注册的事件为SelectionKey.OP_ACCEPT

public void run();//首先将Server类放入到Server变量中;定义一个SelectionKey,并让其一直处于等待监听的状态;当有client传来连接时,通过方法doAccept(key)来与之建立连接,建立连接完成后,将key重置为null;之后单线程控制Listener对象,将acceptChannel和selector都进行关闭,如果此时connectionList不为空的话,则删除其中的第一个连接

private void closeCurrentConnection();//判断SelectionKey是否为null,如若不为null,则获取与之关联的Connection对象,并将其关闭


在这个类中存在一个内部类Reader:

readSelector:这个字段负责Reader的事件监听

public void run();//首先这个reader受控于单个线程,别的线程来了只能去排队;让readSelector一直处于监听状态,直到client传来了调用;当发现client传来了方法调用信息时,获取到这个连接的SelectionKey,判断该是否为可读,可验证,之后调用doRead(key)方法来实现信息读取;完成之后,将SelectionKey重置为null;

public void startAdd();//该方法负责唤醒readSelector,使其不再进入等待监听状态

public synchronized SelectionKey registerChannel(SocketChannel channel) throws IOException;//将channel注册到SelectionKey,注册事件为SelectionKey.OP_READ

public synchronized void finishAdd();//使得readSelector处于等待监听状态


Handler类

public void run();//首先定义一个ByteArrayOutputStream类型的数组,大小为INITIAL_RESP_BUF_SIZE;通过callQueue.take()从call队列中取出第一个call;判断call.connection.user是否为null,如若等于null,则直接调用server端的方法call(call.connection.protocol, call.param, call.timestamp);否则进行进一步处理,call.connection.user.doAs();当获取到调用方法结果后,单线程控制call.connection.responseQueue,通过调用setupResponse(buf, call,  (error == null) ? Status.SUCCESS : Status.ERROR,  value, errorClass, error)方法来实现结果直接返回到client,如果发现返回的结果过大,则需要将结果重新发送,但此时发送是通过Responder来发送的,具体调用方法responder.doRespond(call)来实现


Responder类

private boolean processResponse(LinkedList<Call> responseQueue,boolean inHandler) throws IOException;//首先单线程控制responseQueue,计算responseQueue的大小,如果为空的话,直接返回;否则获取responseQueue中的第一个call对象;通过call获取call.connection.channel,通过调用channelWrite(channel, call.response)直接将call中的responder结果写入到channel中返回给client;如果此时返回成功的话,相应的减少一个rpc连接;否则将channel注册到writeSelector,注册事件为OP_WRITE,并通过channel.register(writeSelector, SelectionKey.OP_WRITE, call)来完成call结果的返回




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值