- 前言
- 远程过程调用(RPC)是一种计算机通信协议,能让一台计算机上的程序调用另一台计算机上的子程序,且程序员操作时就像调用本地程序一样便捷,无需过多考虑底层网络技术细节。例如,在分布式系统中,不同计算机上的程序可以通过 RPC 相互协作。
- 由于实际应用中的差异,RPC 衍生出多种通信协议,如 SUN 公司的 RMI(可视为 RPC 的 Java 版本)和 Google 创建的 gRPC 等。
- 本地过程调用(LPC)
- 概念:在传统编程里,过程或函数由程序员本地编译,它们相互调用且都在本地运行。比如在一个简单的 C 语言程序中,各个函数之间的调用就是本地过程调用,像
main
函数调用其他自定义函数来完成特定功能。 - 优缺点:优点是通过加载类库、内存共享等机制可轻松实现调用;缺点是在分布式和网络环境下,它无法利用其他主机资源,如分布式计算任务中不能调用远程主机的计算能力,也不能很好地共享代码,导致主机资源浪费。
- 概念:在传统编程里,过程或函数由程序员本地编译,它们相互调用且都在本地运行。比如在一个简单的 C 语言程序中,各个函数之间的调用就是本地过程调用,像
- RPC 详解
- 概念:RPC 提供透明调用机制,使开发者不用区分本地和远程调用,能直接调用另一台计算机的函数或方法。比如在一个企业级分布式应用中,客户端程序可以像调用本地函数一样调用远程服务器上的业务逻辑函数。
- 历史:其思想最早可追溯到 1974 年的 RFC 674 草案,1981 年 Nelson 正式提出概念和技术,1984 年 Birrell 和 Nelson 将其用于异构分布式系统通讯。Birrell 的 RPC 模型引入存根进程(stub)和 RPC 运行时库(RPC runtime),这种模式被广泛采用。后来 SUN 公司的 RPC 较典型,经 IETF ONC 宪章修订后,ONC RPC 成为标准协议,在 NFS 和 ONC 等环境中是基本实现技术,很多语言也内置了 RPC 技术。
- 模式与框架结构:采用客户端 - 服务器(Client/Server)模式。为实现透明调用,引入客户句柄(客户端存根 client stub)、网络通信模块(如基于 TCP 或 UDP 的 sockets)和服务器句柄(服务端存根 server stub)。客户端存根负责将请求和参数序列化后发送给服务器,并处理服务器响应;网络通信模块传输数据;服务端存根接收请求、反序列化并触发相应服务程序,再将结果序列化返回给客户端。
- 调用流程:首先调用客户端句柄传送参数,接着调用本地系统内核发送网络消息,消息传送到远程主机后,服务器存根获取消息和参数,执行远程过程,然后将结果返回服务器存根,服务器存根再调用远程系统内核将消息传回本地主机,客户端存根接收内核消息,最后客户端接收句柄返回的数据。整个过程中,RPC 将中间步骤封装,让远程调用看起来像本地调用。例如在一个远程数据查询的 RPC 调用中,客户端发起查询请求,经过这些步骤后得到查询结果。
- 应用
- 分布式操作系统进程间通讯:分布式操作系统中,不同节点机上的进程需要通讯,RPC 是实现消息传送模式通讯的重要手段。比如在一个大规模分布式计算集群的操作系统中,不同节点上的进程通过 RPC 交换数据和协调任务。
- 构造分布式计算软件环境:分布式软件环境各组件地理分散且需大量交互通讯,RPC 是基本实现方法,如 ONC+和 DCE 等环境都基于 RPC 构建。
- 远程数据库服务:在分布式数据库系统里,客户端通过 RPC 调用服务器上的存储过程来访问数据库。像 Sybase 和 Oracle 等数据库都支持这种方式,用户在客户端能方便地操作远程数据库。
- 分布式应用程序设计:为开发者提供便利,无需了解网络结构和协议细节就能设计分布式应用。例如开发一个跨地域的电商应用系统,不同地区的服务模块可以通过 RPC 进行交互。
- 分布式程序调试:利用反向 RPC,服务器可向客户端发出 RPC 来调试程序。比如在服务器上运行调试程序,遇到断点时通知客户端,帮助开发者定位和解决分布式程序中的问题。
- RMI 简介:在 Java 领域,远程调用方法有多种,RMI 是其中之一。它是纯 Java 的网络分布式应用核心解决方案,在 RPC 基础上支持分布式对象间通讯,能实现远程对象无缝调用。其目标包括支持不同 Java 虚拟机上对象的远程调用、服务器回调、集成分布式对象模型到 Java 语言、简化分布式应用开发和保留安全性等。例如在一个 Java 分布式企业级应用中,不同服务器上的 Java 对象可以通过 RMI 进行方法调用和数据交互。
- gRPC 远程调用框架
- 2015 年由 Google 开源,基于 HTTP/2 协议,支持多种编程语言。它通过简单的 IDL(接口定义语言)和强大的代码生成工具(编写
.proto
文件定义服务接口和数据结构,自动生成客户端和服务器代码),方便开发者构建分布式系统。在实际项目中,如开发一个跨国公司的多语言微服务架构应用,gRPC 可以很好地实现不同语言服务之间的高效通信。 - 核心设计思路
- 协议:采用 Http2 协议,具有传输二进制数据、支持双向流(双工)和连接多路复用等特性,能提高数据传输效率。比如在实时数据推送和接收场景中,双向流可以让客户端和服务器随时发送和接收数据,而连接多路复用可以在一个连接上同时处理多个请求,减少连接建立开销。
- 序列化:基于二进制的 ProtocolBuffer 序列化方式,具有跨语言、跨平台特性,相比 JSON 等格式,序列化后数据更小、速度更快。它通过可变长度编码和只存储字段标号等方式优化数据存储和传输。例如在传输大量结构化数据时,ProtocolBuffer 能显著减少网络带宽占用和传输时间。
- 代理创建:让调用者能像调用本地方法一样调用远端方法,提高开发便利性。
- 通信原理:客户端调用时将接口名、方法、参数类型和参数值等发送到服务器,服务器根据这些信息生成代理对象执行相应方法,并序列化结果返回给客户端。比如客户端请求获取用户信息,将相关参数发送后,服务器处理并返回格式化后的用户信息数据。
- 序列化协议:数据传输需序列化和反序列化,不同 RPC 框架使用不同协议,gRPC 采用 ProtocolBuffer。它定义了多种基本类型(如
int32
、int64
等)和结构化数据类型(message
、enum
、map
),通过.proto
文件定义数据结构,并使用编译器生成对应源代码。
- 2015 年由 Google 开源,基于 HTTP/2 协议,支持多种编程语言。它通过简单的 IDL(接口定义语言)和强大的代码生成工具(编写
- gRPC 编程案例(基于 Spring Boot 整合 gRPC)
- Server 端
- 添加依赖:添加
net.devh
提供的相关依赖,这些依赖简化了 gRPC 服务在 Java 应用中的发布和消费等操作,包括服务发布、调用、自动装配、调试等功能。 - 编写
.proto
文件:定义服务接口和数据结构,如示例中的HelloService
,包括请求参数HelloReq
(包含name
字段)和返回参数HelloResp
(包含ret
字段),以及具体的hello
方法。 - 反编译生成 Java 代码:在 pom 文件中配置 protoBuf 插件,执行命令后在指定路径生成相应类文件,这些类文件是基于
.proto
文件定义生成的,用于实现 gRPC 服务端和客户端的逻辑。 - 实现 service 方法:使用
@GrpcService
注解实现服务方法,该注解可自动将服务绑定到 gRPC 服务器,无需手动注册。在hello
方法中,根据请求参数构建返回结果并发送给客户端。 - 配置文件:指定 HTTP 服务端口(如 8080)和 gRPC 服务端口(如 9090)等信息。
- 添加依赖:添加
- Client 端
- 添加依赖:添加相应的客户端依赖。
- 编写
.proto
文件:与 Server 端维护相同的.proto
文件,确保数据结构和接口定义一致。 - 反编译生成 Java 代码:同 Server 端操作,生成客户端所需的类文件。
- 配置文件:配置连接服务器的地址(如
localhost:9090
)、连接保持等参数,如启用保持连接功能(enableKeepAlive
)和指定连接安全类型(negotiationType
)等,同时指定客户端监听端口(如 8081)。 - 调用服务代码编写:使用
@GrpcClient
注解注入服务 stub,在hello
方法中通过 stub 调用远程服务,并返回结果。
- 调用测试:分别启动 Server 端和 Client 端后,在浏览器访问指定地址(如
http://localhost:8081/hello?name=zs
),即可测试 gRPC 服务是否正常工作,应能得到预期的返回结果(如 “你好:zs”)。
- Server 端
远程过程调用(RPC)
最新推荐文章于 2025-02-28 10:21:22 发布