今天分布式应用、云计算、微服务大行其道,作为其技术基石之一的 RPC 你了解多少?一篇 RPC 的技术总结文章,数了下 5k+ 字,略长,可能也不适合休闲的碎片化时间阅读,可以先收藏抽空再细读:)
全文目录如下:
- 定义
- 起源
- 目标
- 分类
- 结构
- 模型
- 拆解
- 组件
- 实现
- 导出
- 导入
- 协议
- 编解码
- 消息头
- 消息体
- 传输
- 执行
- 异常
- 总结
- 参考
两年前写过两篇关于 RPC 的文章,如今回顾发现结构和逻辑略显凌乱,特作整理重新整合成一篇,想了解 RPC 原理的同学可以看看。
近几年的项目中,服务化和微服务化渐渐成为中大型分布式系统架构的主流方式,而 RPC 在其中扮演着关键的作用。 在平时的日常开发中我们都在隐式或显式的使用 RPC,一些刚入行的程序员会感觉 RPC 比较神秘,而一些有多年使用 RPC 经验的程序员虽然使用经验丰富,但有些对其原理也不甚了了。 缺乏对原理层面的理解,往往也会造成开发中的一些误用。
定义
RPC 的全称是 Remote Procedure Call 是一种进程间通信方式。 它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。
起源
RPC 这个概念术语在上世纪 80 年代由 Bruce Jay Nelson(参考[1])提出。 这里我们追溯下当初开发 RPC 的原动机是什么?在 Nelson 的论文 Implementing Remote Procedure Calls(参考[2]) 中他提到了几点:
简单:RPC 概念的语义十分清晰和简单,这样建立分布式计算就更容易。
高效:过程调用看起来十分简单而且高效。
通用:在单机计算中「过程」往往是不同算法部分间最重要的通信机制。
通俗一点说,就是一般程序员对于本地的过程调用很熟悉,那么我们把 RPC 做成和本地调用完全类似,那么就更容易被接受,使用起来毫无障碍。 Nelson 的论文发表于 30 年前,其观点今天看来确实高瞻远瞩,今天我们使用的 RPC 框架基本就是按这个目标来实现的。
目标
RPC 的主要目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。 为实现该目标,RPC 框架需提供一种透明调用机制让使用者不必显式的区分本地调用和远程调用。
分类
RPC 调用分以下两种:
- 同步调用:客户端等待调用执行完成并获取到执行结果。
- 异步调用:客户端调用后不用等待执行结果返回,但依然可以通过回调通知等方式获取返回结果。若客户端不关心调用返回结果,则变成单向异步调用,单向调用不用返回结果。
异步和同步的区分在于是否等待服务端执行完成并返回结果。
结构
下面我们对 RPC 的结构从理论模型到真实组件一步步抽丝剥茧。
模型
最早在 Nelson 的论文中指出实现 RPC 的程序包括 5 个理论模型部分:
User
User-stub
RPCRuntime
Server-stub
Server
这 5 个部分的关系如下图所示:
这里 User 就是 Client 端。当 User 想发起一个远程调用时,它实际是通过本地调用 User-stub。 User-stub 负责将调用的接口、方法和参数通过约定的协议规范进行编码并通过本地的 RPCRuntime 实例传输到远端的实例。 远端 RPCRuntime 实例收到请求后交给 Server-stub 进行解码后发起向