大数据之RPC

1. RPC简介

RPC(Remote Procedure Call),远程过程调用,是一种通过网络从远程计算机进程上请求服务,而无需了解底层网络技术的思想,RPC的出现主要是为了解决分布式系统的通讯问题。

完整的RPC模型

在一个典型 RPC 的使用场景中,包含了服务发现、负载、容错、网络传输、序列化等组件,其中“RPC 协议”就指明了程序如何进行网络传输和序列化(例如使用Netty传输),是RPC的核心功能
在这里插入图片描述

RPC 框架的重要组成:

  • 客户端(Client):服务调用方。
  • 客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
  • 服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
  • 服务端(Server):服务的真正提供者。
  • Network Service:底层传输,可以是 TCP 或 HTTP。

RPC调用流程
一次 RPC 调用流程如下:

  • 服务消费者(Client 客户端)通过本地调用的方式调用服务。
  • 客户端存根(Client Stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体。
  • 客户端存根(Client Stub)找到远程的服务地址,并且将消息通过网络发送给服务端。
  • 服务端存根(Server Stub)收到消息后进行解码(反序列化操作)。
  • 服务端存根(Server Stub)根据解码结果调用本地的服务进行相关处理
  • 服务端(Server)本地服务业务处理。
  • 处理结果返回给服务端存根(Server Stub)。
  • 服务端存根(Server Stub)序列化结果。
  • 服务端存根(Server Stub)将结果通过网络发送至消费方。
  • 客户端存根(Client Stub)接收到消息,并进行解码(反序列化)。
  • 服务消费方得到最终结果。

2. RPC编程模型

在这里插入图片描述
RPC 服务方通过 RpcServer 去导出(export)远程接口方法,而客户方通过 RpcClient 去引入(import)远程接口方法。客户方像调用本地方法一样去调用远程接口方法,RPC 框架提供接口的代理实现,实际的调用将委托给代理RpcProxy代理封装调用信息并将调用转交给RpcInvoker 去实际执行。在客户端的RpcInvoker 通过连接器RpcConnector 去维持与服务端的通道RpcChannel,并使用RpcProtocol 执行协议编码(encode)并将编码后的请求消息通过通道发送给服务方。RPC 服务端接收器 RpcAcceptor 接收客户端的调用请求,同样使用RpcProtocol 执行协议解码(decode)。解码后的调用信息传递给RpcProcessor 去控制处理调用过程,最后再委托调用给RpcInvoker 去实际执行并返回调用结果。如下是各个部分的详细职责:

**1. RpcServer

负责导出(export)远程接口 (方法真正的实现者)

  1. RpcClient

    负责导入(import)远程接口的代理实现

  2. RpcProxy

    远程接口的代理实现

  3. RpcInvoker

    客户方实现:负责编码调用信息和发送调用请求到服务方并等待调用结果返回(可以使用同步机制的wait和notify方法实现)

    服务方实现:负责调用服务端接口的具体实现并返回调用结果

  4. RpcProtocol

    负责协议编/解码

  5. RpcConnector

    负责维持客户方和服务方的连接通道和发送数据到服务方

  6. RpcAcceptor

    负责接收客户方请求并返回请求结果

  7. RpcProcessor

    负责在服务方控制调用过程,包括管理调用线程池、超时时间等

  8. RpcChannel

    数据传输通道**

客户端调用++x ==> 代理对象使用NettyClient编码和发送x,并等待NettyServer返回调用结果 ==> NettyServer解码x,调用服务端实现的++x方法,并返回结果给NettyClient ==> 唤醒代理对象的等待得到结果

3. RPC框架的核心技术点

1. 服务暴露:

远程提供者需要以某种形式提供服务调用相关的信息,包括但不限于服务接口定义、数据结构、或者中间态的服务定义文件。

目前,大部分跨语言平台 RPC 框架采用根据 IDL(IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信交流) 定义通过 code generator 去生成 stub 代码,这种方式下实际导入的过程就是通过代码生成器在编译期完成的。代码生成的方式对跨语言平台 RPC 框架而言是必然的选择,而对于同一语言平台的 RPC 则可以通过共享接口定义来实现。这里的导入方式本质也是一种代码生成技术,只不过是在运行时生成,比静态编译期的代码生成看起来更简洁些。

java 中还有一种比较特殊的调用就是多态,也就是一个接口可能有多个实现,那么远程调用时到底调用哪个?这个本地调用的语义是通过 jvm 提供的引用多态性隐式实现的,那么对于 RPC 来说跨进程的调用就没法隐式实现了。如果接口有 2 个实现,那么在导出接口时就需要特殊标记不同的实现需要,那么远程调用时也需要传递该标记才能调用到正确的实现类,这样就解决了多态调用的语义问题

2. 远程代理对象:

服务调用者用的服务实际是远程服务的本地代理。说白了就是通过动态代理来实现。

java 里至少提供了两种技术来提供动态代码生成,一种是 jdk 动态代理(被代理对象需实现接口),另外一种是字节码生成(cglib被代理对象无需实现接口)。动态代理相比字节码生成使用起来更方便,但动态代理方式在性能上是要逊色于直接的字节码生成的,而字节码生成在代码可读性上要差很多。两者权衡起来,个人认为牺牲一些性能来获得代码可读性和可维护性显得更重要。

3. 通信:(netty囊括以下所有功能)
RPC框架与具体的协议无关。RPC 可基于 HTTP 或 TCP 协议,Web Service 就是基于 HTTP 协议的 RPC,它具有良好的跨平台性,但其性能却不如基于 TCP 协议的 RPC。

  • TCP/HTTP:众所周知,TCP 是传输层协议,HTTP 是应用层协议,而传输层较应用层更加底层,在数据传输方面,越底层越快,因此,在一般情况下,TCP 一定比 HTTP 快。

  • 消息ID:RPC 的应用场景实质是一种可靠的请求应答消息流,和 HTTP 类似。因此选择长连接方式的 TCP 协议会更高效,与 HTTP 不同的是在协议层面我们定义了每个消息的唯一 id,因此可以更容易的复用连接。

  • IO方式:为了支持高并发,传统的阻塞式 IO 显然不太合适,因此我们需要异步的 IO,即 NIO。Java 提供了 NIO 的解决方案,Java 7 也提供了更优秀的 NIO.2 支持。

  • 多连接:既然使用长连接,那么第一个问题是到底 client 和 server 之间需要多少根连接?实际上单连接和多连接在使用上没有区别,对于数据传输量较小的应用类型,单连接基本足够。单连接和多连接最大的区别在于,每根连接都有自己私有的发送和接收缓冲区,因此大数据量传输时分散在不同的连接缓冲区会得到更好的吞吐效率。所以,如果你的数据传输量不足以让单连接的缓冲区一直处于饱和状态的话,那么使用多连接并不会产生任何明显的提升,反而会增加连接管理的开销。

  • 心跳:连接是由 client 端发起建立并维持。如果 client 和 server 之间是直连的,那么连接一般不会中断(当然物理链路故障除外)。如果 client 和 server 连接经过一些负载中转设备,有可能连接一段时间不活跃时会被这些中间设备中断。为了保持连接有必要定时为每个连接发送心跳数据以维持连接不中断。心跳消息是 RPC 框架库使用的内部消息,在前文协议头结构中也有一个专门的心跳位,就是用来标记心跳消息的,它对业务应用透明。

4. Java中常用的RPC框架

  1. Thrift:thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。

  2. Dubbo:Dubbo是一个分布式服务框架,以及SOA治理方案。其功能主要包括:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载均衡与容错,依赖分析与降级等。 Dubbo是阿里巴巴内部的SOA服务化治理方案的核心框架,Dubbo自2011年开源后,已被许多非阿里系公司使用。

  3. Spring Cloud:Spring Cloud由众多子项目组成,如Spring Cloud Config、Spring Cloud Netflix、Spring Cloud Consul 等,提供了搭建分布式系统及微服务常用的工具,如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性token、全局锁、选主、分布式会话和集群状态等,满足了构建微服务所需的所有解决方案。Spring Cloud基于Spring Boot, 使得开发部署极其简单。

5. RPC和消息队列的差异

Message Queue

  1. Message Queue把请求的压力保存一下,逐渐释放出来,让处理者按照自己的节奏来处理。
  2. Message Queue引入一下新的结点,系统的可靠性会受Message Queue结点的影响。
  3. Message Queue是异步单向的消息。发送消息设计成是不需要等待消息处理的完成。
    所以对于有同步返回需求,用Message Queue则变得麻烦了。

RPC

  1. 同步调用,对于要等待返回结果/处理结果的场景,RPC是可以非常自然直觉的使用方式(RPC也可以是异步调用)。
  2. 由于等待结果,Consumer(Client)会有线程消耗。如果以异步RPC的方式使用,Consumer(Client)线程消耗可以去掉。但不能做到像消息一样暂存消息/请求,压力会直接传导到服务Provider。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值