大致了解下Hadoop RPC机制


      RPC是Hadoop的基础组件,提供分布式环境下的对象调用功能。之前用了两天时间分析与测试Hadoop RPC,目的是想弄清楚它对集群协作的影响。本来想等深入研究后再总结,但怕过完十一就忘的差不多了,那就今天写下来。

这节描述三个部分:
1. Hadoop RPC 介绍
2. RPC server端的实体模型
3. 用户对RPC可以有哪些影响

Hadoop RPC介绍
      一般我们所了解的RPC机制都要面对两个问题:对象调用方式和序列/反序列化机制。基于此的RPC产品与框架也很多,但Hadoop却自己实现了简单的RPC组件,依赖于Hadoop Writable类型的支持。Hadoop Writable接口要求每个实现类都得确保将本类的对象正确序列化(writeObject)与反序列化(readObject)。因此,Hadoop RPC使用Java动态代理与反射实现对象调用方式,客户端到服务器数据的序列化与反序列化由Hadoop框架或用户自己来实现,也就是数据组装是定制的。

      简单来说,Hadoop RPC = 动态代理 + 定制好的二进制流。如果不关注细节,从用户的角度来看,它的结构大致像下图




      远程的对象拥有固定的接口,这个接口用户也是可见的,只是真正的实现(Object)只在服务端。用户如果想使用那个实现的话,他的调用过程如此:先根据那个接口动态代理生成一个代理对象,调用这个代理对象的时候,用户的调用请求被RPC捕捉到,然后包装成调用请求,序列化成数据流发送到服务端;服务端从数据流中解析出调用请求,然后根据用户所希望调用的接口,调用接口真正的实现对象,再把调用结果返回给客户端。

      从我个人来看,这种实现很粗犷。它屏蔽了其它框架对Hadoop的影响,对风险可控,又不失性能。这里有Tom Write的一篇文章,他的意思是暂时Hadoop RPC可用,如果其它RPC框架对提高集群性能有帮助的话,Hadoop也会报有开放的心态引入它们。事实上当前Hadoop release已经有与thrift相关的contribution。

RPC server端的实体模型
      上一部分是站在用户的角度,宏观地观察整个调用过程。这节分析下在细节上RPC都有哪些实体。为什么要提到这些实体呢?如果把RPC流程看做流水线的话,这些实体就是一个个做具体工作的工人,如果想深入了解流水线的处理,就得知道每个工作他的职责及概况。

      RPC在客户端的细节不多,只想提一点,就是用户在调用代理对象时RPC是怎样拦截这次调用请求呢。对动态代理清楚的朋友都知道,创建代理对象时需要为它关联一个InvocationHandler,对代理对象的每次调用都会进入绑定的InvocationHandler中,RPC就从这里获取用户的请求,这里没有疑点。[关于动态代理]

      需要详细说的是RPC在服务端的模型,它由一系列实体组成,分别负责调用的整个流程。这里也可以用一张图来描述它们





      从图上看,各个实体分工明确,各司其职。下面我会一一介绍。
Listener
      监听RPC server的端口,如果客户端有连接请求到达,它就接受连接,然后把连接转发到某个Reader,让Reader去读取那个连接的数据。如果有多个Reader的话,当有新连接过来时,就在这些Reader间顺序分发。这里需要提到的是,Hadoop0.21版本在支持多Reader时有个bug(JIRA),如果有Reader在server运行期没被使用,Server进程不能正常关闭
Reader
      Reader的职责就是从某个客户端连接中读取数据流,然后把它转化成调用对象(Call),然后放到调用队列(call queue)里
Handler
      真正做事的实体。它从调用队列中获取调用信息,然后反射调用真正的对象,得到结果,然后再把此次调用放到响应队列(response queue)里
Responder
      它不断地检查响应队列中是否有调用信息,如果有的话,就把调用的结果返回给客户端。

      整个调用流程中与网络有关的地方都是用NIO来处理的。

用户对RPC可以有哪些影响
      对于我们用户来说,Hadoop有自己的默认配置,我们用它提供的服务就成了。但如果对它的调优的想法,那么暂时它提供我们的配置点就有这几个:
1. Reader数量
      正常情况下,一个客户端关联一个Reader,如果有很多客户端(client或DataNode),那么就可以相应增加这个配置
      参数:ipc.server.read.threadpool.size, 默认是1,需要注意的是,这个配置参数是0.21版本的,不同版本的参数可能不一样

2. Handler数量
      对于这种做事的线程,不好把握度,到底多少才是合适。
      参数:dfs.namenode.handler.count, 这里是以NameNode举例
3. 客户端重试次数
      客户端在调用时发生异常,重试是无可厚非。但如果对实时性有要求,那么这里的重试就有考量。Fackbook在做的Realtime分析就有提到RPC的重试是需要修改的
      参数:ipc.client.connect.max.retries, 默认是10
4. tcp no delay
      不建议对它有什么设置。如果我们对整个调用的过程中数据量大小及网络环境不清楚的话,就是设置了也不知道它是否有作用。
      参数:ipc.client.tcpnodelay,默认是false

猜你喜欢

转载自langyu.iteye.com/blog/1183337
今日推荐