最近开始看Hadoop的一些源码,展开hadoop的源码包,各个组件分得比较清楚,于是开始看一下IPC的一些源码。(版本是1.0.4中的ipc包)
IPC模块,也就是进程间通信模块,如果是在不同的机器上,那就可以理解为RPC了,也就是远程调用。事实上,hadoop中的IPC也就是基于RPC实现的。
使用sloccount统计一下ipc包中代码的行数,一共是2884行。也就是说,IPC作为hadoop的基础组件,仅仅用了不到3000行的代码,就完成得稳定且富有效率。
IPC中的关键类关系:
对用户而言,可以直接使用的就是绿色的类。
通过RPC这个门面:
- 客户端可以创建相应的proxy,接着就可以进行远程调用。
- 而服务提供者则可以创建相应的server,并进行相应的生命周期管理(start、stop),从而提供服务。
序列化
从上图也可以看出,client和server的交互,是通过网络connection,而走网络的调用,是需要走序列化/反序列话的过程的。
这个过程,IPC使用了Hadoop的自己的序列化机制,一切都在Writable接口中,只要给定writable的DataOutput和DataInput,就可以让Writable自己实现序列化。
一些问题和思考
- client是单例的吗——可以理解为是,但其实不一定。可以跟踪getProxy的代码,虽然每次都会新建一个代理对象,但底层的Client还是和SocketFactory对应的。一般默认的,都是使用默认的SocketFactory,但如果你设置了”hadoop.rpc.socket.factory.class.default”,则会有新的Client与你自定义的SocketFactory对应。这时候,client就不是单例的。
- client与同一个server有几个连接——一个client与一个server只有一个连接,具体可以看生成的代理中,有一个remoteId,这个remoteId是和client关联的,client进行调用的使用,会将此remoteId作为一个connectionId。因此,一般一个client是一个连接。
- 如果client是一个连接,那么对此client的调用,不都是串行的吗?——看你怎么理解了,在用户层面,也就是client调用的方法,是可以并发的。client底层是使用一个连接来进可能的完成吞吐量。每个request和response都会有一个id关联起来。因此一个连接上可以跑满请求和相应。
- 由于网络问题,client调用服务失败后,有重试机制吗——在IPC中没有看到call的重试,需要上层去保证了。但是后面的调用会重新建立连接。
- server是单例的吗——不一定。如果你只getServer一次的话。创建一个server的代价是非常重的。通过上图你也可以知道,他需要有一个线程(Listener)来acceptsocket,同时需要一些Reader线程来进行socket的read,还有一个Responder来进行socket的write,另外,还有若干个handler线程来进行业务处理。因此,如果可以减少server的个数,就应该减少server个数。
- 暴露出的服务是否应该是线程安全的——是的,一定要线程安全。server底层是通过nio进行socket操作的,因此虽然只有一个线程负责accept,但是能够支持很多的client连接。这些连接在到达server端之后,很有可能就会并发执行同一方法(如果你的业务handler不止一个的话)
- 一个server要消耗多少线程资源?——让我们来算一下,一个Listener线程,若干个Reader线程(默认1个),若干个Handler线程(在getServer的时候指定,一般1-10个),一个Responder线程。如果都按照默认值来计算的话。最少需要1+1+1+1=4个线程。也许,不应该算多,如果请求量不大的话,这些线程应该都被blocked住的。
总结
- Hadoop的IPC是一个比较轻量级别的RPC
- 从代码来看,只支持java进程之间的通信
- 从没有重试机制、一个Client只有一个连接的机制来看,适合与应用网络环境较好的场景,适合同机架或者同机房的集群。
P.S.看了一下io包中,其实有个retry的package,里面就是一个重试机制。奇怪的是为啥这个package被包含在iopackage中。
VIA:zavakid
更多详细信息,请您微信关注“计算网”公众号: