一、概述

RPC 传输层需要把序列化后的字节流数据传给服务端,然后再把序列化后的调用结果传回客户端。只要能完成这两者的,都可以作为传输层使用。因此,尽管大部分 RPC 框架都使用 TCP 协议,但其实 UDP 也可以,而 gRPC 千脆就用了 HTTP2, Spark RPC 基于 Netty 实现了 RPC 通信服务传输层,

二、架构设计

Spark 底层通信全部使用 Netty 进行了替换, 传输上下文 TransportContext 是 NettyRpcEnv 提供服务端与客户端能力的前提,TransportContext 内部包含传输上下文的配置信息 TransportConf 和对客户端请求消息进行处理的 RpcHandler。TransportConf 在创建 TransportClientFactory 和 TransportServer 时都是必需的, 而 RpcHandler 只用于创建 TransportServer。

2.1. 客户端

TransportClientFactory 是 RPC 客户端的工厂类。在构造 TransportClientFactory 的实例时,会传递客户端引导程序 TransportClientBootstrap 的列表。此外,TransportClientFactory 内部还存在针对每个 Socket 地址的连接池 ClientPool。

有了 TransportClientFactory,Spark 的各个模块就可以使用它创建 RPC 传输层客户端 TransportClient啦~

2.2. 服务端

TransportServer是 RPC 服务端的实现。通过调用 $TransportContext.createServer()$ 方法创建传输服务端 TransportSever 的实例。在构造 TransportServer 的实例时,需要传递 TransportContext、host、port、RpcHandler 及服务端引导程序 TransportServerBootstrap 的列表。

2.3. Channel

NIO 网络编程模型中,IO 操作直接和 channel 相关,比如客户端的请求连接,或者向服务端发送数 据,服务端都要从客户端的 channel 获取这个数据 Netty 在服务端初始化和新连接建立的过程中会建立相应的 Channel,而与 Channel 的动作密切相关的是 Pipeline 这个概念,pipeline 可以看作是一条流水线,原始的原料(字节流)进来,经过加工,最后输出。

2.3.1. Netty Handler

Handler 在 Netty 中占据着非常重要的地位。通过 Handler 可以完成通讯报文的解码编码、拦截指定的报文、统一对日志错误进行处理、统一对请求进行计数、控制 Handler 执行与否。

Netty 中的所有 handler 都实现自 ChannelHandler 接口。按照输出输出来分,分为 ChannelInboundHandler、ChannelOutboundHandler 两大类。

  • ChannelInboundHandler 对从客户端发往服务器的报文进行处理,一般用来执行解码、读取客户端数据、进行业务处理等
  • ChannelOutboundHandler 对从服务器发往客户端的报文进行处理,一般用来进行编码、发送报文到客户端

Netty 中,可以注册多个 handler。ChannelInboundHandler 按照注册的先后顺序执行;ChannelOutboundHandler 按照注册的先后顺序逆序执行。

2.3.2. Spark Rpc Handler

1
2
3
4
5
6
pipeline
.addLast("encoder", ENCODER)
.addLast(TransportFrameDecoder.HANDLER_NAME, NettyUtils.createFrameDecoder())
.addLast("decoder", DECODER)
.addLast("idleStateHandler", new IdleStateHandler(0, 0, conf.connectionTimeoutMs() / 1000))
.addLast("handler", channelHandler);
  1. LoggingHandler

  2. MessageEncoder

  3. TransportFrameDecoder

  4. MessageDecoder

  5. IdleStateHandler

  6. TransportChannelHandler

    当 TransportChannelHandler 读取到的 request 是 RequestMessage 类型时,则将此消息的处理进一步交给 TransportRequestHandler,当 request 是 ResponseMessage 时,则将此消息的处理进一步交给 TransporResponseHandler。

    由协议层的实现知道,最终的消息实现类都直接或间接地实现了 RequestMessage 或 ResponseMessage 接口,在 RPC 传输层中创建的所有通道都是双向的。当客户端使用 RequestMessage 启动 Netty 通道(由服务端的 TransportRequestHandler 处理)时,服务端也会生成 ResponseMessage (由客户端的 TransportRequestHandler 处理)。

    服务端也会在同一个 Channel 上获取句柄,向客户端发送 RequestMessages。所以客户端还需要一个 RequestHandler,而 Server 需要一个 ResponselHandler,用于客户端对服务端请求的响应。

  7. ChunkFetchRequestHandler