RPC 是远程过程调用(Remote Procedure Call),即远程调用其他虚拟机中运行的 java object。

本文深入剖析了HadoopRPC的工作原理,包括其在HDFS中的应用,RPC的客户端/服务器模式,序列化与反序列化,以及网络通信。HadoopRPC通过动态代理和反射实现方法调用,采用NIO Reactor模式提升服务器性能。此外,文章还探讨了如何配置和优化RPC服务器,以及FairCallQueue在处理RPC拥塞中的作用。
摘要由CSDN通过智能技术生成

HDFS之RPC

RPC 是远程过程调用(Remote Procedure Call),即远程调用其他虚拟机中运行的 java object。

RPC 是一种客户端/服务器模式,那么在使用时包括服务端代码和客户端代码,还有我们调用的远程过程对象。HDFS 的运行就是建立在此基础之上的。本文通过分析实现一个简单的 RPC 程序来分析HDFS 的运行机理。

HDSF 作为分布式文件系统,常常涉及 DataNode、NameNode、Client 之间的配合、相互调用才能完成完整的流程。为了降低节点之间的耦合性,HDFS 将节点间的调用抽象成不同的接口,其接口主要分为两类:HadoopRPC 接口和基于 TCP 或 HTTP 的流式接口。流式接口主要用于数据传输,HadoopRPC 接口主要用于方法调用。HadoopRPC 框架设计巧妙,本文将结合 hadoop2.7 源码,对 HadoopRPC 做初步剖析。

RPC工作原理

RPC(Remote Procedure Call)即远程过程调用,是一种通过网络从远程计算机程序上请求服务的协议。RPC允许本地程序像调用本地方法一样调用远程计算机上的应用程序,其使用常见的网络传输协议(如TCP或UDP)传递RPC请求以及相应信息,使得分布式程序的开发更加容易。

RPC采用客户端/服务器模式,请求程序就是客户端,服务提供程序就是服务器。RPC框架工作原理如图1所示,工作流程依次见图中标号①~⑩,其结构主要包含以下部分:
在这里插入图片描述

  • client functions

    请求程序,会像调用本地方法一样调用客户端stub程序(如图中①),然后接受stub程序的响应信息(如图中⑩)

  • client stub

    客户端stub程序,表现得就像本地程序一样,但底层却会调用请求和参数序列化并通过通信模块发送给服务器(如图中②);客户端stub程序也会等待服务器的响应信息(如图中⑨),将响应信息反序列化并返回给请求程序(如图中⑩)

  • sockets

    网络通信模块,用于传输RPC请求和响应(如图中的③⑧),可以基于TCP或UDP协议

  • server stub

    服务端stub程序,会接收客户端发送的请求和参数(如图中④)并反序列化,根据调用信息触发对应的服务程序(如图中⑤),然后将服务程序的响应信息(如图⑥),并序列化并发回给客户端(如图中⑦)

  • server functions

    服务程序,会接收服务端stub程序的调用请求(如图中⑤),执行对应的逻辑并返回执行结果(如图中⑥)那么要实现RPC框架,基本上要解决三大问题:

  • 函数/方法识别

    sever functions如何识别client functions请求及参数,并执行函数调用。java 中可利用反射可达到预期目标。

  • 序列化及反序列化

    如何将请求及参数序列化成网络传输的字节类型,反之还原请求及参数。已有主流的序列化框架如 protobuf、avro 等。

  • 网络通信

    java 提供网络编程支持如 NIO。

主流的 RPC 框架,除 HadoopRPC 外,还有 gRPC、Thrift、Hessian 等,以及 Dubbo 和 SpringCloud 中的 RPC 模块,在此不再赘述。下文将解读 HDFS 中 HadoopRPC 的实现。

HadoopRPC架构设计

HadoopRPC 实现了图 1 中所示的结构,其实现主要在 org.apache.hadoop.ipc 包下,主要由三个类组成:RPC 类、Client 类和Server 类。HadoopRPC 实现了基于 TCP/IP/Sockets 的网络通信功能。客户端可以通过 Client 类将序列化的请求发送到远程服务器,服务器会通过 Server 类接收客户端的请求。

客户端 Client 在收到请求后,会将请求序列化,然后调用 Client.call() 方法发送请求到到远程服务器。为使 RPC 机制更加健壮,HadoopRPC 允许配置不同的序列化框架如 protobuf。Client 将序列化的请求 rpcRequest 封装成 Writable 类型用于网络传输。具体解析见下节—— RPC Client 解读。

服务端 Server 采用 java NIO 提供的基于 Reactor 设计模式。Sever 接收到一个 RPC Writable 类型请求后,会调用 Server.call() 方法响应这个请求,并返回 Writable 类型作为响应结果。具体解析见下节—— RPC Server 解读。

RPC 类提供一个统一的接口,在客户端可以获取 RPC 协议代理对象,在服务端可以调用 build() 构造 Server 类,并调用 start() 启动 Server 对象监听并响应 RPC 请求。同时,RPC 类提供 setProtocolEngine() 为客户端或服务端适配当前使用的序列化引擎。RPC 的主要两大接口如下:
public static ProtocolProxy getProxy/waitForProxy(…):构造一个客户端代理对象(该对象实现了某个协议),用于向服务器发送RPC请求。
public static Server RPC.Builder(Configuration).build():为某个协议(实际上是Java接口)实例构造一个服务器对象,用于处理客户端发送的请求

那么,如何使用HadoopRPC呢?只需按如下4个步骤:

  1. 定义RPC协议
    RPC协议是客户端和服务器端之间的通信接口,它定义了服务器端对外提供的服务接口。如ClientProtocol定义了HDFS客户端与NameNode的通信接口, ClientDatanodeProtocol定义了HDFS客户端与DataNode的通信接口等。

  2. 实现RPC协议
    对接口的实现,将会调用Server端的接口的实现。

  3. 构造并启动RPC Server
    构造Server并监听请求。可使用静态类Builder构造一个RPC Server,并调用函数start()启动该Server,如:

RPC.Server server = new RPC.Builder(conf).setProtocol(MyProxyProtocol.class)
        .setInstance(new MyProxy())
        .setBindAddress(HOST)
        .setNumHandlers(2)
        .setPort(PORT)
        .build();
server.start();
  1. 构造RPC Client并发送请求

构造客户端代理对象,当有请求时客户端将通过动态代理,调用代理方法进行后续实现,如:

MyProxyProtocol proxy = RPC.getProxy(MyProxyProtocol.class,    MyProxyProtocol.versionID,        new InetSocketAddress(HOST, PORT), conf);XXX result = proxy.fun(args);

RPC Client解读

在 IPC(Inter-Process Communication)发生之前,客户端需要通过 RPC 提供的 getProxy 或 waitForProxy 获得代理对象,以 getProxy 的具体实现为例。RPC.getProxy 直接调用了 RPC.getProtocolProxy 方法,getProtocolProxy 方法如下:

public static <T> ProtocolProxy<T> getProtocolProxy(...) throws IOException {
   
   ...
   return getProtocolEngine(protocol, conf).getProxy
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值