作者:dxj20101118 | 来源:互联网 | 2023-02-04 19:00
摘要:大概解释了什么是rpc以及rpc的注意事项,还有各个rpc框架
RPC(Remote Procedure Call),远程过程调用。它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想,RPC是一种技术思想,而非具体的一种规范或协议。在先介绍远程过程调用之前,然后再介绍一下什么是本地调用,皮一下,嘿嘿。就是你想次饭,然后自己去厨房做了开火,炒菜焖饭,顶天就是开个多线程,同时做这些事情,做完了之后还得自己屁颠屁颠的端到饭桌上,开次。远程过程调用就是你打开饿了么,订了个外卖,厨师去厨房炒菜做饭,你不用去自己做这些事情,只需要等待外卖小哥(网络传输层)把好吃的饭菜(数据结果)送过来。这么说,是不是很容易理解。
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/8a024746e5d96a3f.png)
个人理解,rpc的起源为分布式,是分布式促使了rpc的诞生。
如何实现一个RPC
在我看来,一个高性能的RPC应该尽量避免使用http协议,毕竟我只是想传输一下数据而已,何必动用到一个文本传输的应用层协议呢,应该使用一些效率更高的通信协议,比如说UDP或者是TCP,但是不管你用何种协议进行数据传输,一个简化版的RPC框架结构如同下图
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/274d5374a30f9065.png)
从上图可以看出, RPC 本身是 client-server模型,也是一种 request-response 协议。
有些实现扩展了远程调用的模型,实现了双向的服务调用,但是不管怎样,调用过程还是由一个客户端发起,服务器端提供响应,基本模型没有变化。
服务的调用过程为:
- client调用client stub,这是一次本地过程调用
- client stub将参数打包成一个消息,然后发送这个消息。打包过程也叫做 marshalling
- client所在的系统将消息发送给server
- server的的系统将收到的包传给server stub
- server stub解包得到参数。 解包也被称作 unmarshalling
- 最后server stub调用服务过程. 返回结果按照相反的步骤传给client
为了不了解微服务的童鞋好理解,先抛出了一个简易的流程图。但是在项目当中来说一个完整的微服务不仅仅是只有上图那些东西,还有服务注册,服务发现、负载、容错、网络传输、序列化,反序列化等组件。其中“RPC 协议”就指明了程序如何进行网络传输和序列化。
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/1c0c36d0605e6815.png)
简单的常见问题
1、服务端如何确定客户端要调用的函数;
在远程调用中,客户端和服务端分别维护一个【ID->函数】的对应表, ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,附上这个ID,服务端通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。
2、如何进行序列化和反序列化;
客户端和服务端交互时将参数或结果转化为字节流在网络中传输,那么数据转化为字节流的或者将字节流转换成能读取的固定格式时就需要进行序列化和反序列化,序列化和反序列化的速度也会影响远程调用的效率。
只有二进制数据才能在网络中传输,序列化和反序列化的定义是:
- 将对象转换成二进制流的过程叫做序列化
- 将二进制流转换成对象的过程叫做反序列化
3、如何进行网络传输(选择何种网络协议);
多数RPC框架选择TCP作为传输协议,也有部分选择HTTP。如gRPC使用HTTP2。不同的协议各有利弊。TCP更加高效,而HTTP在实际应用中更加的灵活。
4、服务注册中心;
服务注册中心用来实现服务发现和服务的元数据存储。常见的服务注册中心,点对点,点对多,zookeeper,etcd,Consul,mDNS等
常见的微服务框架
目前流行的开源 RPC 框架还是比较多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle ,以及国人开发的rpcx。
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/54d28f145191b9ff.png)
- gRPC:是 Google 公布的开源软件,基于最新的 HTTP 2.0 协议,并支持常见的众多编程语言。RPC 框架是基于 HTTP 协议实现的,底层使用到了 Netty 框架的支持。
- Thrift:是 Facebook 的开源 RPC 框架,主要是一个跨语言的服务开发框架。
用户只要在其之上进行二次开发就行,应用对于底层的 RPC 通讯等都是透明的。不过这个对于用户来说需要学习特定领域语言这个特性,还是有一定成本的。
- Rpcx:是一个分布式的Go语言的 RPC 框架,支持Zookepper、etcd、consul多种服务发现方式,多种服务路由方式, 是目前性能最好的 RPC 框架之一。
- Dubbo:是阿里集团开源的一个极为出名的 RPC 框架,在很多互联网公司和企业应用中广泛使用。协议和序列化框架都可以插拔是极其鲜明的特色。
如下是一个Dubbo的设计架构图,分层清晰,功能复杂,嗯,极其复杂
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/20935cccf5e33906.png)
哦吼,真是
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/e6ec65c28418aaa6.png)
RPC详解
1.RPC 核心之网络传输协议
在 RPC 中可选的网络传输方式有多种,可以是 TCP 协议、KCP协议、UDP 协议、QUIC协议,HTTP1以及HTTP2 协议。
每一种通信协议对业务的性能和效率都有不同的影响,如何选择一个正确的网络传输协议呢?首先要搞明白各种传输协议在 RPC 中的工作方式。
接下来我主要介绍TCP跟HTTP的调用流程以及区别
基于 TCP 协议的 RPC 调用
由微服务的客户端以及服务端建立 Socket 连接,并由客户端通过 Socket 将需要调用的接口名称,方法名称,序列化后的数据传递给服务端处理,然后服务端通过反序列化后的信息反射调用相关的方法。
最后将处理好的结果返回给客户端。整体流程基本上就是这样。
基于 HTTP 协议的 RPC 调用
该方法更像是访问网页一样,只是它的返回结果更加单一简单。
大致流程为:由微服务的客户端向服务端发送请求,这种请求的方式可能是 GET、POST、PUT、DELETE 等中的任意一种,服务端会根据不同的请求方式做出不同的处理,或者某个方法只允许某种请求方式。
而调用的具体方法则是根据 URL 进行方法调用,而方法所需要的参数可能是对服务调用方传输过去的 XML 数据或者 JSON 数据解析后的结果,最后返回 JOSN 或者 XML 的数据结果。
两种方式对比
基于 TCP 的协议实现的 RPC 调用, TCP 协议处于协议栈的下层,能够更加灵活地对协议字段进行定制,减少网络开销,提高性能,实现更大的吞吐量和并发数。但是需要更多关注底层复杂的细节,实现的代价更高。同时对应不同应用平台,需要选择不同的工具包来进行请求发送和相应解析,工作量大。
基于 HTTP 协议实现的 RPC 则可以使用 JSON 和 XML等 格式的请求或响应数据。json以及xml等通用格式标准在各个编程语言下的解析工具已经非常成熟,不需要过多的关注。所以说在其基础上进行开发会非常简单。但是正是由于http的可靠以及简单。所以相对比TCP协议更加的效率低还有耗资源。因为http协议是上层协议。要包含更多的内容信息,来保证其可靠性。所以说在网络传输要占用的更多的字节数。
因此在同等网络下,通过 HTTP 协议传输相同内容,效率会比基于 TCP 协议的数据效率要低,信息传输所占用的时间也会更长,当然压缩数据,能够缩小这一差距。
使用 RabbitMQ 的 RPC 架构
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/9e55645e34fb20d7.png)
在 OpenStack 中服务与服务之间使用 RESTful API 调用,而在服务内部则使用 RPC 调用各个功能模块。
正是由于使用了 RPC 来解耦服务内部功能模块,使得 OpenStack 的服务拥有扩展性强,耦合性低等优点。
OpenStack 的 RPC 架构中,加入了消息队列 RabbitMQ,这样做的目的是为了保证 RPC 在消息传递过程中的安全性和稳定性。
使用 RabbitMQ 的好处:
- 同步变异步:可以使用线程池将同步变成异步,但是缺点是要自己实现线程池,并且强耦合。使用消息队列可以轻松将同步请求变成异步请求。
- 低内聚高耦合:解耦,减少依赖。
- 流量削峰:通过消息队列设置请求最大值,超过阀值的抛弃或者转到错误界面。
- 网络通信性能提高:TCP 的创建和销毁消耗的资源很大,高峰时成千上万条的链接会造成资源的巨大浪费,而且操作系统每秒处理 TCP 的数量也是有数量限制的,必定造成性能瓶颈。而RabbitMQ 采用信道通信,不采用 TCP 直接通信。一条线程一条信道,多条线程多条信道,公用一个 TCP 连接。一个TCP可以容纳无限个通道(只要你硬盘够大),不会造成性能浪费
RabbitMQ 的三种类型的交换器
RabbitMQ 使用 Exchange(交换机)和 Queue(队列)来实现消息队列。
在 RabbitMQ 中一共有三种交换机类型,每一种交换机类型都有很鲜明的特征。
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/d898b4eea7a296ee.png)
广播式交换器(Fanout)
该类型交换器不分析所接收到消息中的 Routing Key,默认将消息转发到所有与该交换器绑定的队列中去。
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/b9899d13cc08e618.png)
直接式交换器(Direct)
该类交换器需要精确匹配 Routing Key 与 Binding Key,如消息的 Routing Key = Cloud,那么该条消息只能被转发至 Binding Key = Cloud 的消息队列中去。
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/d1b07755d8be70fe.png)
主题式交换器
该类交换器通过消息的 Routing Key 与 Binding Key 的模式匹配,将消息转发至所有符合绑定规则的队列中。
Binding Key 支持通配符,其中“*”匹配一个词组,“#”匹配多个词组(包括零个)
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/97f695d0a90ef245.png)
RabbitMQ连接设计
RabbitMQ 实现的 RPC 对网络的一般设计思路:消费者是长连接,发送者是短连接。但可以自由控制长连接和短连接。
一般消费者是长连接,随时准备接收处理消息;而且涉及到 RabbitMQ Queues、Exchange 的 auto-deleted 等没特殊需求没必要做短连接。发送者可以使用短连接,不会长期占住端口号,节省端口资源。
Protobuf
介绍:Protocol Buffers 是一种与语言、平台无关,可扩展的序列化结构化数据的方法,常用于通信协议,数据存储等等。相较于 JSON、XML,它更小、更快、更简单,因此也更受开发人员的青眯
![在这里插入图片描述](https://img1.php1.cn/3cd4a/250c2/978/8f09c85533daac07.png)
相较 Protobuf,为什么不使用XML?
- 更简单
- 数据描述文件只需原来的1/10至1/3
- 解析速度是原来的20倍至100倍
- 减少了二义性
- 生成了更易使用的数据访问类
REST与RPC比较
都是网络交互的协议规范。通常用于多个微服务之间的通信协议。
比较 |
REST |
REST |
---|
通信协议 |
HTTP |
一般使用TCP |
性能 |
低 |
高 |
灵活度 |
高 |
低 |
REST和RPC都可以应用于微服务架构中。
- HTTP相对更规范,更标准,更通用,无论哪种语言都支持http协议。如果你是对外开放的API,例如开放平台,想调用API的编程语言多种多样,无法拒绝对每种语言的支持,所以说最先支持的应该包含RESTful。
- RPC 框架作为架构微服务化的基础组件,它能大大降低架构微服务化的成本,提高调用方与服务提供方的研发效率,屏蔽跨进程调用函数(服务)的各类复杂细节。让调用方感觉就像调用本地函数一样调用远端函数、让服务提供方感觉就像实现一个本地函数一样来实现服务。
最后对REST与RPC做一个小小的总结,REST的调用以及调试都特别方便 ,RPC跟起对比就麻烦一些,但是RPC的效率以及对分布式的支持以及动态扩容能力是毋庸置疑的,所以建议在分布式的内部调用的时候使用RPC,对外部提供服务的时候使用REST。