RPC(远程过程调用)
RPC 远程过程调用
RPC(Remote Process Call),远程过程调用,常用作服务内部的通讯,让构建分布式计算更容易,在提供强大的远程调用能力时又不失本地调用的语义简洁性。为此,RPC框架需要提供一种透明调用机制,让使用者不必显式地区分本地调用和远程调用。
RPC初步
RPC是在上世纪80年代出现的一种技术,用于分布式系统内部的通讯,具有分布式设计、部署灵活、解构服务、扩展性强等优点。
RPC不应该被理解成一种固定的协议,而是一种思想。设想一个场景:现在有多个主机在同网络中,每个主机中都运行了一个或多个服务,并且这些主机作为一个整体需要向局域网外的某个客户端或者网页提供服务,那么这些主机上的服务之间势必要进行一些通讯来保证互相之间的数据传输或者维护数据的一致性。有网络编程知识的会立刻想到要使用socket来互相发消息,为了保证连接的可靠,传输层选择TCP协议,那么轻松地(bushi)就可以撸出来一套网络通讯服务,比如某个主机上的订单服务(order server)提供了下单和查询订单功能,只要你把带有函数名和参数的数据包发送过来,订单服务就可以执行对应的方法。那么我在用户服务(user server)上去查单,只需要执行以下几步:
- user server调用
connect
连接到order server。 - 连接成功后,user server组好数据包,数据包中包含了查询订单的函数和对应的参数。
- 将这个数据包发送给order server
- order server接收到数据包后解析出对应的方法和参数
- order server执行对应的方法得到结果
- order server将结果也组成数据包返回给user server,调用结束。
分析上述过程,可以抽象出整个流程:连接
->组包
->发送
->解包
->执行业务
->回包
。每次调用都需要写一大堆重复的代码,属实麻烦,如果能像直接调用本地函数一样调用远程的方法就好了。你看,RPC这不就来了嘛。我在user server中也写一个函数,就叫queryOrder
1 | void queryOrder() { |
而在order server上,在收到这个数据包就调用自己的queryOrder
函数,并返回数据包就好了,在外部看来,查询就好像是调用了本地的函数一样。
特性
- RPC框架一般使用长链接,不必每次通信都要3次握手,减少网络开销。
- RPC框架一般都有注册中心,有丰富的监控管理。发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作协议私密,安全性较高
- RPC 协议更简单内容更小,效率更高,服务化架构、服务化治理,RPC框架是一个强力的支撑。
架构
一个RPC框架大概需要完成上述这些模块,思路和上述我们的想法其实没有多少差别,只是补充了诸多工程实践上的细节,比如负载均衡、容错、线程池等。
调用流程
这可以看作是对上述我们想法的细化,其中抽象出了接收数据包和将数据包与二进制数据流转换的过程,具象化为client stub(客户端存根)和server stub(服务器存根)。这两者的任务就是将数据序列化成二进制流并通过网络传输出去和将接收到的二进制流反序列化成对应的数据。
其中涉及到以下一些技术。
- 动态代理
生成client stub和server stub时需要使用动态代理技术(似乎是java中的概念,不太了解)。
问了一下chatgpt,如下:“动态代理(Dynamic Proxy)是一种设计模式,它允许在运行时创建代理对象,而无需在编译时确定具体的代理类。动态代理通常用于在调用对象的方法时添加额外的逻辑,如日志记录、性能监视、安全控制等。在Java中,动态代理通常通过 java.lang.reflect.Proxy 类实现。使用动态代理,你可以在运行时创建一个代理类,该代理类实现了指定的接口,并将方法调用转发到一个或多个委托对象(被代理对象)。动态代理背后的核心思想是:在运行时动态生成字节码,以创建代理对象,而不需要在编译时知道具体的被代理类。动态代理的主要优点之一是可以减少重复的代码,并将横切关注点(cross-cutting concerns)从核心业务逻辑中分离出来,从而提高代码的模块化和可维护性。”
看起来很高大上,又是设计模式,又是反射的,不过好像就是将可能会被执行的方法封装成一个统一的接口暴露出来,然后在运行的时候通过一些方法来指定执行哪个,C++中也能通过函数指针或者仿函数等方法实现吧。
- 序列化
将数据转换成二进制字节流的过程称为序列化,将二进制字节流再转换成数据的过程称为反序列化。当然,数据也不是随便就能转的,需要遵循提前设定好的规则或者是特定的结构才能转,可以使用一些框架来实现,比如
fastjson
、protobuf
等。
- 通讯
这部分没啥好说的,就是网络通讯嘛,针对各种网络传输问题,也有大量的库可供选择。
- 服务注册中心
客户端想要连接并调用服务端发布的服务需要通过服务注册中心,实际上就是个中间的数据库,服务器有哪些服务,就将服务信息注册到这个数据库中,然后客户端需要调用的时候就去这个库里查有没有,有的话怎么连接和调用。主流的注册中心比如
redis
,zookeeper
等。
- 负载均衡
这对应的高并发的场景,不能“一核有难,八核围观”,要合理得分配多个节点或集群的任务来提高整体的吞吐能力。
- 健康检查
就是节点之间周期性的互相问候一下,看看是不是还活着,常用心跳帧或者服务器主动探测两种方法。
一些RPC框架
框架 | |
---|---|
Dubbo | 国内最早开源的 RPC 框架,由阿里巴巴公司开发并于 2011 年末对外开源,仅支持 Java 语言。 |
Motan | 微博内部使用的 RPC 框架,于 2016 年对外开源,仅支持 Java 语言。 |
Tars | 腾讯内部使用的 RPC 框架,于 2017 年对外开源,仅支持 C++ 语言。 |
SpringCloud | 国外 Pivotal 公司 2014 年对外开源的 RPC 框架,提供了丰富的生态组件。 |
gRPC | Google 于 2015 年对外开源的跨语言 RPC 框架,支持多种语言。 |
Thrift | 最初是由 Facebook 开发的内部系统跨语言的 RPC 框架,2007 年贡献给了 Apache 基金,成为Apache 开源项目之一,支持多种语言。 |
参考文章https://zhuanlan.zhihu.com/p/374901408
参考文章https://www.zhihu.com/question/524580708