首页天道酬勤rpc底层原理,rpc协议详解

rpc底层原理,rpc协议详解

张世龙 05-13 12:07 8次浏览

33558 www.Sina.com/RPC (远程过程调用) :远程过程调用。 服务调用方可以像调用本地接口一样调用远程服务提供方。 RPC框架屏蔽基本传输方法(TCP或UDP )、序列化方法(XML/Json/二进制)和通信详细信息,而不考虑基本通信详细信息和调用过程。

RPC是技术思想而不是规范和协议,目前流行的开源RPC框架还很多,有阿里巴巴的杜比、脸书的Thrift、谷歌的gRPC、推特的Finagle等。

为什么需要RPC? 随着项目规模和复杂性的增加,需要对项目进行服务化和划分

将单个APP应用程序划分为多个服务后的优点:

1 .降低项目臃肿程度,按业务维度划分服务后,各团队集中在负责的业务线,职责单一化

2 .解除服务之间的耦合,各项服务可以配置合适的研发人员,独立开发,与合适的技术堆栈独立配置

项目服务化后,会出现一些问题。

一个业务功能请求需要经过多个服务间呼叫最终完成。 每个服务都是独立部署的,不能像在单个APP应用程序中那样在本地调用。 如何实现服务间呼叫呢?

RPC概念::调用方和调用方约定协议格式,通过套接字通信传输参数,调用方监听套接字,根据接收到的参数调用本地方法

缺点:呼叫方和被呼叫方每次都必须关注基础呼叫的详细情况

条目被反序列化为字节流,字节流被反序列化为参数套接字传输协议,套接字为方式一

是的。 RPC框架解决了这个问题,它允许调用方“像调用本地函数一样调用远程函数(服务)”。

33558 www.Sina.com/:在RPC框架中完成服务之间的调用

能不能调用层不关注这个细节?

3358www.Sina.com//序列化、连接池管理、负载平衡、路由策略、故障转移、超时处理、异步管理等3358www.Sina.com//网络通信事件处理

在业务程序中,通常在“对象”中处理数据,但如果需要将数据转换为方式二PRC框架的职责是,“对象”就非常有用在许多情况下,需要将数据转换为连续空间的“二进制流”。 典型的场景如下。

数据库Client端:数据库索引在内存中是b树,但不能直接存储在磁盘上。 因此,磁盘上的Server端:如果redis/memcache是KV类型的缓存,则必须将b树转换为连续空间的二进制流。存储在缓存中的value将: socket发送的数据必须是连续空间的二进制流,不一定是对象的所谓http://www.Sina.com/(serialization ),相反过程为http://www.sinn

为什么要进行序列化?

通过使用自描述标记语言(如json和xml )编写对象并定义转换规则,发送方更容易将对象序列化为xml,而服务端在收到xml二进制流后更容易将其反序列化为对象。 通过自定义和序列化二进制协议,以谷歌的http://www.Sina.com/(Pb )为中心进行介绍

存储典型的RPC使用场景包括服务发现、负载、容错、网络传输、串行化等组件,“RPC协议”由程序在网上

传输

同步调用是指在获得结果之前保持阻止状态,并继续占用工作线程。 上图简要介绍了组件、交互和过程的步骤。

3358www.Sina.com/表示被调用工作线程的左侧3358www.Sina.com/,RPC-client组件的右侧3358www.Sina.com/表示RPC-serrer 表示序列化组件和连接池组件索引的磁盘存储,以及箭头1-10,表示整个工作线程的串行执行过程。 1 )业务代码开始调用RPC。

result=add(obj1,Obj2)2)调用序列化组件、对象

序列化成二进制字节流,可理解为一个待发送的包packet1;

3)通过连接池组件拿到一个可用的连接connection;

4)通过连接connection将包packet1发送给RPC-server;

5)发送包在网络传输,发给RPC-server;

6)响应包在网络传输,发回给RPC-client;

7)通过连接connection从RPC-server收取响应包packet2;

8)通过连接池组件,将conneciont放回连接池;

9)序列化组件,将packet2范序列化为Result对象返回给调用方;

10)业务代码获取Result结果,工作线程继续往下走;

 

rpc的核心功能:

RPC 的核心功能是指实现一个 RPC 最重要的功能模块,就是上图中的”RPC 协议”部分:

 

一个 RPC 的核心功能主要有 5 个部分组成,分别是:客户端、客户端 Stub、网络传输模块、服务端 Stub、服务端等。

注:

stub 

每个远程对象都包含一个代理对象stub,当运行在本地Java虚拟机上的程序调用运行在远程Java虚拟机上的对象方法时,它首先在本地创建该对象的代理对象stub, 然后调用代理对象上匹配的方法,代理对象会作如下工作: 
与远程对象所在的虚拟机建立连接 
打包(marshal)参数并发送到远程虚拟机 
等待执行结果 
解包(unmarshal)返回值或返回的错误 
返回调用结果给调用程序 
stub 对象负责调用参数和返回值的流化(serialization)、打包解包,以及网络层的通讯过程。 

下面分别介绍核心 RPC 框架的重要组成:

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

一次 RPC 调用流程如下:

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

 

RPC 核心之功能实现(技术点)

RPC 的核心功能主要由 5 个模块组成,如果想要自己实现一个 RPC,最简单的方式要实现三个技术点,分别是:

服务寻址(服务的消费放如何找到定位服务的提供者)数据流的序列化和反序列化网络传输

服务寻址

服务寻址可以使用 Call ID 映射。在本地调用中,函数体是直接通过函数指针来指定的,但是在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。

所以在 RPC 中,所有的函数都必须有自己的一个 ID。这个 ID 在所有进程中都是唯一确定的。

客户端在做远程过程调用时,必须附上这个 ID。然后我们还需要在客户端和服务端分别维护一个函数和Call ID的对应表。

当客户端需要进行远程调用时,它就查一下这个表,找出相应的 Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。

实现方式:服务注册中心。

要调用服务,首先你需要一个服务注册中心去查询对方服务都有哪些实例。Dubbo 的服务注册中心是可以配置的,官方推荐使用 Zookeeper。

实现案例:RMI(Remote Method Invocation,远程方法调用)也就是 RPC 本身的实现方式。

图 9:RMI 架构图

Registry(服务发现):借助 JNDI 发布并调用了 RMI 服务。实际上,JNDI 就是一个注册表,服务端将服务对象放入到注册表中,客户端从注册表中获取服务对象。

RMI 服务在服务端实现之后需要注册到 RMI Server 上,然后客户端从指定的 RMI 地址上 Lookup 服务,调用该服务对应的方法即可完成远程方法调用。

Registry 是个很重要的功能,当服务端开发完服务之后,要对外暴露,如果没有服务注册,则客户端是无从调用的,即使服务端的服务就在那里。

序列化和反序列化

客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。

但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。

这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。

只有二进制数据才能在网络中传输,序列化和反序列化的定义是:

将对象转换成二进制流的过程叫做序列化将二进制流转换成对象的过程叫做反序列化

这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。

网络传输

网络传输:远程调用往往用在网络上,客户端和服务端是通过网络连接的。

所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把 Call ID 和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。

只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。

尽管大部分 RPC 框架都使用 TCP 协议,但其实 UDP 也可以,而 gRPC 干脆就用了 HTTP2。

TCP 的连接是最常见的,简要分析基于 TCP 的连接:通常 TCP 连接可以是按需连接(需要调用的时候就先建立连接,调用结束后就立马断掉),也可以是长连接(客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效),多个远程过程调用共享同一个连接。

所以,要实现一个 RPC 框架,只需要把以下三点实现了就基本完成了:

Call ID 映射:可以直接使用函数字符串,也可以使用整数 ID。映射表一般就是一个哈希表。序列化反序列化:可以自己写,也可以使用 Protobuf 或者 FlatBuffers 之类的。网络传输库:可以自己写 Socket,或者用 Asio,ZeroMQ,Netty 之类。

RPC 核心之网络传输协议

在第三节中说明了要实现一个 RPC,需要选择网络传输的方式。

图 10:网络传输

在 RPC 中可选的网络传输方式有多种,可以选择 TCP 协议、UDP 协议、HTTP 协议。

每一种协议对整体的性能和效率都有不同的影响,如何选择一个正确的网络传输协议呢?首先要搞明白各种传输协议在 RPC 中的工作方式。

基于 TCP 协议的 RPC 调用

由服务的调用方与服务的提供方建立 Socket 连接,并由服务的调用方通过 Socket 将需要调用的接口名称、方法名称和参数序列化后传递给服务的提供方,服务的提供方反序列化后再利用反射调用相关的方法。

***将结果返回给服务的调用方,整个基于 TCP 协议的 RPC 调用大致如此。

但是在实例应用中则会进行一系列的封装,如 RMI 便是在 TCP 协议上传递可序列化的 Java 对象。

基于 HTTP 协议的 RPC 调用

该方法更像是访问网页一样,只是它的返回结果更加单一简单。

其大致流程为:由服务的调用者向服务的提供者发送请求,这种请求的方式可能是 GET、POST、PUT、DELETE 等中的一种,服务的提供者可能会根据不同的请求方式做出不同的处理,或者某个方法只允许某种请求方式。

而调用的具体方法则是根据 URL 进行方法调用,而方法所需要的参数可能是对服务调用方传输过去的 XML 数据或者 JSON 数据解析后的结果,***返回 JOSN 或者 XML 的数据结果。

由于目前有很多开源的 Web 服务器,如 Tomcat,所以其实现起来更加容易,就像做 Web 项目一样。

两种方式对比

基于 TCP 的协议实现的 RPC 调用,由于 TCP 协议处于协议栈的下层,能够更加灵活地对协议字段进行定制,减少网络开销,提高性能,实现更大的吞吐量和并发数。

但是需要更多关注底层复杂的细节,实现的代价更高。同时对不同平台,如安卓,iOS 等,需要重新开发出不同的工具包来进行请求发送和相应解析,工作量大,难以快速响应和满足用户需求。

基于 HTTP 协议实现的 RPC 则可以使用 JSON 和 XML 格式的请求或响应数据。

而 JSON 和 XML 作为通用的格式标准(使用 HTTP 协议也需要序列化和反序列化,不过这不是该协议下关心的内容,成熟的 Web 程序已经做好了序列化内容),开源的解析工具已经相当成熟,在其上进行二次开发会非常便捷和简单。

但是由于 HTTP 协议是上层协议,发送包含同等内容的信息,使用 HTTP 协议传输所占用的字节数会比使用 TCP 协议传输所占用的字节数更高。

因此在同等网络下,通过 HTTP 协议传输相同内容,效率会比基于 TCP 协议的数据效率要低,信息传输所占用的时间也会更长,当然压缩数据,能够缩小这一差距。

 

为什么有了http还要用RPC?

具体使用哪一种要看实际的业务场景,各有优缺点,灵活站位。

HTTP协议,以其中的Restful规范为代表,其优势很大。优点在于:它可读性好,且可以得到防火墙的支持、跨语言的支持

HTTP协议缺点:①首先是传输数据包有用信息占比少,包含了大量的HTTP头等信息。②效率低,传输相同的内容,时间长,效率低。③使用HTTP协议调用远程方法比较复杂,要封装各种参数名和参数值,在易用性上没rpc强。

1.主要的关注点就在于,基于http协议的resultFul风格的接口调用和rpc的传输协议(比如使用tcp协议)的一个区别。但是所谓的效率优势是针对http1.1协议来讲的,http2.0协议已经优化编码效率问题,像grpc这种rpc库使用的就是http2.0协议。

2.成熟的rpc库相对http容器,更多的是封装了“服务发现”,"负载均衡",“熔断降级”一类面向服务的高级特性。针对服务的可用性和效率等都做了优化。单纯使用http调用则缺少了这些特性。

 

 

 

https://developer.51cto.com/art/201906/597963.htm

https://zhuanlan.zhihu.com/p/266261432

 

Houye的论文解读,Houye的论文 python rabbitmq,socketio python