一、概述

那么,当请求到达服务器端之后,服务器端是如何响应的呢🤔️~

获取了 BlockingService 对象后,ProtoBufRpcInvoker 利用调用信息中的调用方法信息(在这个例子中是 rename)和调用参数对象(RenameRequestProto)调用 BlockingService.callBlockingMethod() 方法响应 RPC 请求。

RpcServer

NameNodeRpcServer 初始化

二、传输层 Server

Server 对象用于监听并响应来自 RPC 客户端的请求。例如对于 Namenode,它会构造两个 Server 对象分别响应来自 HDFS 客户端和 Datanode 的 RPC 请求。

2.1. Server 初始化

本节就以 Namenode 构造 Server的流程为例~,看看👀~RPC 服务器端获取 Server 对象的代码实现~

clientRpcServer 和 serviceRpcServer 的构造方法很类似,都是先调用 RPC.build()方法获取一个 RPC.Server 对象,然后调用
DFSUtil.addPBProtocol() 方法在新获取的 RPC.Server 对象上添加 *ProtocoIPB 协议与 BlockingService 对象之间的映射关系

例如 ClientNamenodeProtocolPB 协议会由 BlockingService 对象: clientNNPbService 处理。之所以配置这个映射关系,是因为当 RPC.Server监听到网络上的 RPC 请求后,它会首先提取出RPC 请求的请求头域,解析出这次 RPC 请求是在什么接口(接口信息)的什么方法([方法信息)上调用的,然后根据接口信息以及上述配置的映射关系提取出执行响应操作的 BlockingService 对象,最后根据方法信息调用
BlockingService.callBlockingMethod() 方法响应这个 RPC 调用。

所以*ProtocolPB 协议接口与BlockingService 对象之间的映射关系保证了 RPC 请求到达 Server 后,Server 可以找到正确的响应类来执行相应操作。

三、Stub 程序

服务器端 Stub 程序会将通信模块接收的数据反序列化,然后调用服务程序对应的方法响应这个 RPC 请求。不同的 RpcEngine 会实现自己的 Server 对象(RPC.Server 的子类),Server 对象会实现一个内部的 RpcInvoker 对象

3.1. 反序列化

ProtobufRpcEngine 实现了内部类 Server,而 Server 类又定义了自己的 ProtoBufRpcInvoker 类。这个 ProtoButRpcInvoker 对象会使用 protobuf 反序列化 RPC 请求(RpcRequestWrapper 类型),然后调用服务程序响应这个请求,最后 ProtoBufRpcInvoker 会将响应消息序列化包装成一个RpcResponseWrapper 对象并返回。

callBlockingMethod() 方法根据调用方法信息判断这是一个 ClientNamenodeProtocolPB.rename() 调用,它会在 ClientNamenodeProtocolServerSideTranslatorPB 对象上调用 rename(RenameRequestProto)方法响应,ClientNamenodeProtocolServerSideTranslatorPB.rename() 方法会将 RenameRequestProto 参数反序列化成两个 String 参数,

3.2. 协议层

3.3. 路由层

ProtoBufRpcInvoker 对象会将请求数据反序列化,解析出调用信息和调用参数。之后 ProtoBufRpcInvoker 对象会根据调用信息中的调用接口信息(在这个例子中是 ClientProtocol)查找实现了 ClientProtocol 接口的 BlockingService 对象,这个 BlockingService 对象持有一个实现了 ClientNamenodeProtocolPB 接口的 ClientNamenodeProtocolServerSideTranslatorPB 对象,用于响应 ClientNamenodeProtocoIPB 接口上的调用。

四、服务程序

在持有的实现了 ClientProtocol 接口的 NameNodeRpcServer 上调用 rename(String,String) 方法响应,在 Namenode 的命名空间中更改指定 HDFS 文件的名称,最后返回响应信息。ClientNamenodeProtocolServerSideTranslatorPB 接收到 NameNodeRpcServer 的响应信息后会将这个响应包装成一个 protobuf 序列化的 RenameResponseProto 对象,然后返回到 ProtoBufRpcInvoker。

ProtoBufRpcInvoker 接收到 RenameResponseProto 这个响应对象后,由于 ProtoBufRpcInvoker.call() 方法的返回值定义是
Writable 类型的,ProtoBufRpclnvoker 会构造一个 RpcResponseWrapper 对象包装 RenameResponseProto,然后将这个对象返回给 RPC Client。

五、总结