Hadoop IPC源码分析(一)

Hadoop IPC源码分析(一)

 

RPC

 

RPC包含了一系列的静态类和静态方法。

使用PROTOCOL_ENGINES = new HashMap<Class,RpcEngine>();

作为实现的接口—>RPCEngine的一个缓存

 

使用PROXY_ENGINES = new HashMap<Class,RpcEngine>();

作为实现的接口代理->PPCEngine的一个缓存

 

接口代理使用JDKProxy.getProxyClass获取对应接口的代理类。

默认的RpcEngine的实现为  WritableRpcEngine.class ;

 

waitForProxy方法是在时间限制内周期的调用getProxy方法,而getProxy是从缓存中获取接口所对应的RpcEngine实例,具体的Proxy获取由RpcEgine接口实现类实现。

 

RPC类管理一系列的PpcEnginegetProxy getServer call stopProxy方法的实际工作是由RpcEgine实现的。

 

接口RpcEngine

 

接口定义了getProxy getServer call stopProxy几个方法。

 

getProxy用于获取客户端代理,getProxy方法包含了一个InetSocketAddress addr参数,用于指定PPC服务器的地址和一个SocketFactory factory用于创建客户端到服务器之间的连接。

 

getSever用于构建PRC服务器端,getServer有一个Object instance参数,此参数代表接口实现的类。PPC服务器将请求转发给instance实例处理。

 

call方法参数包含一个请求参数列表数组Object[][] params和一组PPC服务器地址InetSocketAddress[] addrs和需要执行的方法Method method。一次call请求可以同时请求多个服务器。

 

RpcEgine有两种实现AvroRpcEngineWritableRpcEngine

 

WritableRpcEngine

 

WritableRpcEngine使用Invocation类表示一次方法调用,一次调用包含调用的函数名、参数类型和参数值信息。

 

Map<SocketFactory, Client> clients = new HashMap<SocketFactory, Client>();

每一个client和一个SocktFactory是对应的,一个节点上建立了几个SocketFactory对象就有几个client。这里说明client不是每次方法调用的时候都新建一个客户端,而是一个进程类所有的调用都用同一个客户端。

 

使用JDK RPC框架实现ProxyProxy将接口任务转交给Invocker处理,Invocker类实现了InvocationHandler接口。在Invocker类的实现中,由将方法调用转发给client类。

 

每次调用接口方法是,都会先获取一个client,增加client引用计数,调用完毕后,减少client引用计数,当client引用计数为0的时候,将client从缓存中移除。

 

Call方法的实现中,没有用到JDK的动态代理,直接将需要调用的方法给client实例处理了。

 

Server复写了Rpc.Servercall方法,Rpccall方法实现的是一次方法的调用,与RpcEngine中的call方法不同的,在此类中的call方法中添加了一些统计功能。

 

这个类命名为WritablePpcEngine主要体现在两点:

1.    代理中的invoke方法中调用了clinetcall方法,call方法的参数Invocation是一个Writable实现类;

2.       server的实现中,servercall方法接收的是一个Writable的类。

 

总之,调用过程中传递参数是通过Writable的实现类Invocation包装的。

 

下面分析两个真正做事的类Client类和Server类。

 

Client

 

首先分析Clientcall方法。Clientcall方法接收Invocation参数,将参数打包为一个Call对象,每一个Call对象都有一个唯一的id,Call包含了此次方法调用是否成功,返回值的信息。

 

Call对象通过一个Connection对象发送出去,然后调用Object.wait()方法循环等待,如果中间线程被中断,忽略中断继续等待,当call对象被notify的时候返回,而后取出Call对象的value的值。

 

那么Call对象的value值是什么时候被设置的呢?Connection有一个receiveResponse方法,当收到相应Callid是,将此id对应的callvalue值设置,然后notify等待中的call

 

Connection用一个Hashtable<Integer, Call> calls维护在此连接上的方法调用。

 

下面看一次方法调用时,怎样获得连接对象的。一个client使用Hashtable<ConnectionId, Connection> connections来维护在此client上的连接池。

 

一个Connection是有ConnectionId标识的,相同的远端地址,接口和用户有相同的ConnectionId。一个Call获取Connection的时候,获取到的Connection也将此Call加入到其维护的calls中。此后,connection会进行一些IO流的设置操作。

 

下面看connection在设置IO流的过程中做了些什么事情。

 

如果是第一次使用connection,有两件事情要做:

1.    向服务器写RPC请求头;

2.    启动此连接上等待RPC回应的线程。

 

如果不是第一次使用此connection,直接返回。

 

PRC请求头中开始几个字母为hrpc,向服务器表明这是一个RPC连接,然后是版本号和验证方式。

 

然后写入与请求的接口服务和请求用户身份信息。

 

此连接上的线程循环判断是否有工作要做,如果calls不为空,就调用receiveResponse方法接收服务器的响应。

 

响应由CallId、方法调用状态和调用返回值组成,如果方法调用状态成功,则将对应的Callcalls中移除,通知等待结果的调用方法。

 

ParallelCallParallelResult不分析。

 

Server

 

Server的实现比Client要复杂。

首先分析类Server的构造函数和启动过程。在Server的构造函数中设置了监听端口,处理队列大小,元素为Call对象的阻塞队列,初始化ListenerResponder

 

serverstart方法中,做了以下一些工作。

1.    启动Responder线程

2.    启动Listener线程

3.    启动handlerCountHandler线程

 

然后分别看看这几个线程是做什么用,怎么工作的。

 

Listener

 

这个类的实现用到了concurrent并发包和nio的一些东西。

 

Listener的构造函数中,打开了一个ServerSocketChannel,并为之绑定监听地址。每个Listner有一个selector,将服务器通道的OP_ACCEPT时间在selector上注册为感兴趣事件。建立一个固定大小的线程池,用于执行多个Reader线程,多个Reader线程以同一个readSelector为构造参数。

 

下面看看Reader到底是干什么的。

Reader线程阻塞在readSelectorselect方法上,等待有感兴趣的事件发生或者有线程调用wakeup方法。当有感兴趣的事情发生时,遍历对应的SelectionKey进行读取操作。读取操作在doRead方法中完成。

 

每个SelectionKey关联了一个Server.Connection对象。得到了Connection对象后,就可以进行读取和处理Connection对象数据上的事情了。

 

现在来看看Connection对象怎么注册到readSelector上的。原来是在Listner线程中发生了selector感兴趣的OP_ACCEPT事件后。当有OP_ACCEPT事件发生时,说明客户端数据已经准备好了,调用accept后就得到服务器与客户端的套接字通道。

 

得到套接字通道后,以round-robin的方式选择一个Reader,将channelOP_READ事件注册在readSelector上。并以当前的客户端服务器channel新建一个Connection,附在注册感兴趣事件返回的SelectionKey上面。最后将得到的connection加入到connectionList中进行维护。

 

现在回过头来看看Listner主线程在干什么,Listner循环阻塞在selector.select方法上面,获取感兴趣的OP_ACCEPT事件。

 

了解完了Listner类是干什么的,上面有提到处理数据是在count = c.readAndProcess();中完成的,下面分析Connection类。

 

Connection

 

主要分析ConnectionreadAndProcess方法。

(待续)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值