RPC你了解吗?

2,476 阅读10分钟

1 RPC

今天和大家一起学习一下 RPC,还是老规矩,秉承 " 最基础的也是最重要的,最重要的也是最简单的 ",不搞那么花哨。

通过本文你将了解到以下内容:

  • 什么是 RPC 和为什么需要它

  • RPC 的重要组件

  • 常见 RPC 框架和各自特点

废话不说,发车发车!

图来自网络: 好奇号火星车

2 什么是 RPC 以及为什么需要它


RPC 是 1984 年代由 Andrew D. Birrell & Bruce Jay Nelson 提出的,所以并不是最近的概念,在二位大神的论文 "Implementing Remote Procedure Calls" :

Implementing Remote Procedure Calls pages.cs.wisc.edu/~sschang/OS…

设计目标:

Make distributed computing easy: let the programmer focus on fundamental difficulty of distributed computing: timing, independent failure of components.

Make RPC communication highly efficient: don't distort program by making programmer avoid communication due to its slowness

Make the semantics of RPC as powerful as possible without loss of simplicity or efficiency

Provide secure communication

简单概括就是让分布式系统更加简单,让开发人员把精力放到业务上,并且提供高效安全的通信。

再来看看比较常见的解释,了解下 RPC 是啥:

RPC(Remote Procedure Call) 远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。也就是说两台服务器 A,B,一个应用部署在 A 服务器上,想要调用 B 服务器上应用提供的方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

大白话理解这段话就是说:RPC 让你用别人家的东西就像自己家的一样。

听得我似懂非懂,于是我不得不问几个问题:

  • 为啥要用别人家的东西 (请求其他服务)

  • 我怎么可以借到别人家的东西 (其他服务调用)

  • 要是借用的话哪种形式更好 (确定一个合适的调用方法)

  • 怎么让我用别人东西像自己的一样 (屏蔽底层细节透明通信)

阐述 RPC 之前我们必须达到一个共识问题:RPC 只是一种通信模式,和 http 并不冲突对立,相反 http 可以作为 RPC 传输数据的一种协议,把 RPC 当作一种模式和思想,我们才能更好地理解它。

2.1 为什么要请求其他服务

典型的 B/S 模型或者 C/S 模型都是客户端要调用服务端接口来获取数据和结果,这种属于外部调用。

区别于外部调用,内部系统随着业务规模的扩大,出现了分布式和微服务,简单说就是把一个庞大的业务拆分成很多子服务,并且每个子服务都部署在很多独立分布的机器上,从而形成一个庞大的内部系统。

生活也是如此,自给自足的农耕经济早已经过去,不同的社会分工有不同的公司团体机构,我们要想完成自己的日常就难免和其他单位实体进行交互。

还是举一个例子:比如我们用 QQ 音乐听歌,感兴趣的歌曲会做成歌单,当手机端用户先用手机号 / 邮箱 / 第三方账号等进行登陆,登录之后进入的自己主页,拉取自己喜欢的歌曲歌单,最后点击播放,这个过程就涉及到多个服务的相互调用,如图:

庞大的单体程序好像逐渐没有市场了,取而代之的是拆分之后的诸多独立功能的服务,它们之间必然存在相互调用来实现一个综合的功能。

2.2 如何调用其他服务

在日常业务中我们可以把功能封装成静态库、动态库、sdk、独立服务等,最常见也最方便的还是 http 这种形式的调用。

http 服务把需要提供的服务暴露成接口,使用方直接按约定的 http 方法和 uri 进行数据交互。

我们都知道 http 协议是应用层协议,是个非常标准的协议,在 http 协议之下还有网络层、传输层、数据链路层等,一个数据包 packet 除了净荷 payload 之外还有很多 header,由于标准和通用性的设计目标也使得 http 一次数据交互真正传输的 payload 只是其中一部分。

图来自网络:http 数据包格式

http 是我们用的最多最熟悉的交互模式,在系统内部各个服务之间接口较少,交互不多的情况下工作得还不错。

在内部系统调用很复杂的前提下,http 调用的效率和安全性就不那么理想了,更重要的是面对众多的服务我们需要的不仅仅是一个通信方式,而是一个内部服务的管理系统,这也就是我们今天说的 RPC 框架,注意 RPC 是一种模式策略和框架,并不是单纯的通信协议。

2.3 实现远程调用的一些思路

前面说了 RPC 远程过程调用就是让服务 A 像调用本地功能一样调用远端的服务 B 上的功能,不要把这个事情想的太悬乎,想想我们本地调用时需要哪些东西:确定的类或函数、类或函数的参数、类或函数的返回值。

远程调用肯定也不会缺少这三要素,唯一的区别在于这三要素是要被传输过去的,这其中就涉及协议编码和解码的过程。

机器 10.1.1.1 上部署了服务 A,机器 10.1.1.2 上部署了服务 B,并且服务 B 上有一个 add 函数,int add(int a,int b), 参数是两个 int 返回值是 int。

这样服务 A 需要通过网络传输来告诉服务 B,它想要 add 函数,传入的两个参数分别是 3 和 5,返回的结果放在 result 里面就可以。

传输的报文里面按照约定的协议格式给出了函数名和参数,大致这样:

上述的编码只是一种举例不代表实际应用,旨在说明本地调用和远程调用的唯一区别就是传输基本要素的方式不同,不要想的太复杂。

为了提高传输效率可以进行二进制编码,比如 protobuf 这种。当然还有其他问题,就不再详细展开了,这些都是我们在设计一个 RPC 框架时需要考虑的点。

2.4 关于 http 和 RPC 的一些辩论

http 和 rpc 是两个很容易混淆的概念,最开始接触 rpc 的时候,我就在想有 http 了为什么还要用 rpc?  在知乎上看到了这个很有趣的问题:

在知乎上有个很好的问题: 既然有 http 请求,为什么还要用 rpc? 详情戳:www.zhihu.com/question/41…

其中一个大佬的回答感觉很有意思:

这个问题的诸多回答其实都表达了一个重要观点:RPC 是一种编程模式和概念,并不是非常具体的一种技术,并且和 http 没有明确的冲突,http 可以作为 RPC 传输协议,更重要的是 RPC 是一种内部服务框架,可以涉及服务注册、服务治理、服务发现、熔断机制、负载均衡等。

3 典型的 RPC 框架组件


前面提到了 rpc 不是简单的一种协议或者技术,而是一种模式和框架,其典型的组成,如图:

图来自网络:rpc 典型组成

RPC 协议模块是很重要的部分,这部分也是前面提到的服务 A 调用服务 B 时传输报文的过程,如图:

图来自网络:rpc 协议组成

其中的序列化和反序列化定义:

序列化:将数据结构或对象转换成二进制串的过程。

反序列化:将序列化中所生成的二进制串转换成数据结构或者对象的过程。

在网络消息传输中可以基于 TCP、UDP、http 来实现,各自都有各自的特点:

基于 TCP 实现的 RPC 调用,能够灵活对协议字段进行定制,减少网络开销提高性能,实现更大的吞吐量和并发数,但要关注底层细节,在进行数据解析时更加复杂一些。

基于 HTTP 实现的 RPC 可以使用 JSON 和 XML 格式的请求或响应数据,解析工具很成熟,在其上进行二次开发会非常便捷和简单。但是 HTTP 是上层协议,所占用的字节数会比使用 TCP 协议传输所占用的字节数更高。

对于其他部分,本文不再展开。

4 常见的 RPC 框架和各自特点


Dubbo 是阿里巴巴公司开源的一个 Java 高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring 框架无缝集成。

Motan 是新浪微博开源的一个 Java 框架。它诞生的比较晚,起于 2013 年,2016 年 5 月开源。Motan 在微博平台中已经广泛应用,每天为数百个服务完成近千亿次的调用。

rpcx 是 Go 语言生态圈的 Dubbo, 比 Dubbo 更轻量实现了 Dubbo 的许多特性,借助于 Go 语言优秀的并发特性和简洁语法,可以使用较少的代码实现分布式的 RPC 服务。

gRPC 是 Google 开发的高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。本身它不是分布式的,所以要实现上面的框架的功能需要进一步的开发。

thrift 是 Apache 的一个跨语言的高性能的服务框架,也得到了广泛的应用,Thrift 是 Facebook 于 2007 年开发的,它提供多语言的编译功能,通过 Thrift 的 IDL 来描述接口函数及数据类型,通过 Thrift 的编译环境生成各种语言类型的接口文件。

brpc(baidu-rpc) 是百度开发一款远过程调用网络框架。目前该项目已在 github 上开源,brpc 目前被应用于百度公司内部各种核心业务上,其中包括高性能计算和模型训练和各种索引和排序服务,且有超过 100 万以上个实例是基于 brpc 工作的。

Tars 是腾讯根据内部多年使用微服务架构的实践,总结而成的开源项目,仅支持 C++ 语言,目前在腾讯内部应用也非常广泛。

其中关于 brpc 在知乎有个很好的问题,其中有包括大神戈君 (brpc 主导者) 在内的多个回答,可以帮助我们快速了解 brpc 框架:

如何评价百度开源的 RPC 框架 brpc?www.zhihu.com/question/65…

tars 和 brpc 是非常不错的开源项目,尤其作为 C++ 程序员很推荐阅读。

5 巨人的肩膀


本文转码, 原文地址 mp.weixin.qq.com