• IPC和RPC?

RPC

RPCRemote Procedure Call),又叫做远程过程调用。它本身并不是一个具体的协议,而是一种调用方式

用户只要在其之前进行二次开发就行,对于底层的 RPC 通讯等都是透明的。不过这个对于用户来说的话需要学习特定领域语言这个特性,还是有一定成本的。

什么是RPC

RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。

也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。为什么要用RPC呢?就是无法在一个进程内,甚至一个计算机内通过本地调用的方式完成的需求,比如不同的系统间的通讯,甚至不同的组织间的通讯,由于计算能力需要横向扩展,需要在多台机器组成的集群上部署应用。RPC就是要像调用本地的函数一样去调远程函数;

推荐阅读文章:https://www.jianshu.com/p/2accc2840a1b

RPC基本原理

图片

stub可以理解为存根

  • **客户端存根,**存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方。
  • 服务端存根,接收客户端发送过来的消息,将消息解包,并调用本地的方法。

一般包括客户端、服务器端、服务注册中心

**◎客户端存根:**用于存放服务器端的地址信息,将客户端的请求参数等信息打包成网络消息,再通过网络传输发送给服务器端。

**◎服务器端存根:**接收客户端发送过来的请求消息并解包,然后调用本地服务处理。

存根之间通过网络传输

同步调用和异步调用

这个过程有点类似于 Java 中的 Callable 和 Runnable 接口,我们进行异步执行的时候,如果需要知道执行的结果,就可以使用 Callable 接口,并且可以通过 Future 类获取到异步执行的结果信息。并提前写上对结果的操作逻辑。

如果不关心执行的结果,直接使用 Runnable 接口就可以了,因为它不返回结果,当然啦,Callable 也是可以的,我们不去获取 Future 就可以了。

步骤解析:

图片

RPC两个核心模块:通讯,序列化。

RPC主要基于TCP/IP

IDL:接口描述语言

调用方法=方法名+参数+返回值

RPC 框架的好处就显示出来了,首先就是长链接,不必每次通信都要像 HTTP 一样去 3 次握手什么的,减少了网络开销。

其次就是 RPC 框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作。

RPC框架-组件简介

gRPC 是 Google 最近公布的开源软件,基于最新的 HTTP2.0 协议,并支持常见的众多编程语言。

Dubbo 是阿里集团开源的一个极为出名的 RPC 框架,在很多互联网公司和企业应用中广泛使用。协议和序列化框架都可以插拔是及其鲜明的特色。

同样的远程接口是基于 Java Interface,并且依托于 Spring 框架方便开发。可以方便的打包成单一文件,独立进程运行,和现在的微服务概念一致。

Thrift 是 Facebook 的一个开源项目,主要是一个跨语言的服务开发框架。它有一个代码生成器来对它所定义的 IDL 定义文件自动生成服务代码框架。

gRPC

gRPC 是 Google 最近公布的开源软件,基于最新的 HTTP2.0 协议,并支持常见的众多编程语言。底层使用到了 Netty 框架的支持。

服务端:

监听端口,注册服务,启动服务器

客户端:

调用函数,传参数,接收返回值

客户端只有接口,用动态代理的方式实例化接口,在invoke方法中获取方法名等信息发给服务端

proto文件(IDL)

框架:

自定义RPC协议

header+body

RPC IO 优化

任何服务都是类似的,大量请求过来时,得用线程池、异步、协程等各种手段优化,提高并发,从而提高吞吐,减小延迟。

有的 RPC 框架能解决这些问题,比如有些 RPC 框架内置协程模型,支持 M 比 N 模型、协程窃取等等。如果 RPC 框架不管,就需要用额外的线程池库、异步库(promise、future)、协程库来手动控制请求的执行流并发执行。

RPC的由来(AI生成)

RPC(Remote Procedure Call,远程过程调用)的诞生源于分布式系统发展的需求。其核心思想是让开发者像调用本地函数一样调用远程服务,从而简化网络通信的复杂性。以下是其关键演进历程:


1. 早期网络通信的痛点(1980年代前)

在分布式系统初期,开发者需直接处理底层网络协议(如TCP/IP)、数据序列化、错误处理等细节。例如,实现跨机器交互需手动编写以下逻辑:

# 伪代码:传统网络调用
socket = create_socket(server_ip)
serialize_data = convert_to_bytes(request_data)
send(socket, serialize_data)
response_data = receive(socket)
result = parse_bytes(response_data)

这种模式导致代码冗余、易出错,且难以维护。


2. 理论突破:Birrell & Nelson的论文(1984)

Bruce Jay Nelson和Andrew Birrell在论文《Implementing Remote Procedure Calls》中首次提出RPC框架:

  • 核心创新:通过存根(Stub)机制屏蔽网络细节
    • 客户端存根:将本地调用封装为网络消息
    • 服务端存根:将网络消息解包为本地调用
  • 调用流程
    Client→Client Stub→Network→Server Stub→ServerServer→Server Stub→Network→Client Stub→Client \begin{align} &\text{Client} \to \text{Client Stub} \to \text{Network} \to \text{Server Stub} \to \text{Server} \\ &\text{Server} \to \text{Server Stub} \to \text{Network} \to \text{Client Stub} \to \text{Client} \end{align} ClientClient StubNetworkServer StubServerServerServer StubNetworkClient StubClient
  • 效果:开发者只需关注业务逻辑,如:
    # RPC调用伪代码
    result = remote_service.add(3, 5)  # 如同本地函数
    

3. 技术落地:Sun RPC与ONC RPC(1980年代末)

Sun Microsystems将理论工程化,推出Sun RPC(后成为开放网络计算RPC,即ONC RPC):

  • 接口定义语言(IDL):通过rpcgen工具定义服务接口(如.x文件)
    // 示例:add.x
    program ADD_PROG {
      version ADD_VERS {
        int add(int, int) = 1;
      } = 1;
    } = 0x20000001;
    
  • 跨语言支持:自动生成C语言存根代码,实现客户端/服务端解耦
  • 标准化:成为UNIX系统的基础设施(如NFS文件系统依赖RPC)

4. 扩展与演进(1990年代后)

  • CORBA:面向对象的跨语言RPC框架
  • XML-RPC/SOAP:基于HTTP/XML的Web服务协议
  • gRPC:Google推出的高性能框架,基于HTTP/2和Protocol Buffers
    // Protocol Buffers定义
    service Calculator {
      rpc Add (AddRequest) returns (AddResponse) {}
    }
    message AddRequest {
      int32 a = 1;
      int32 b = 2;
    }
    

5. 核心价值

RPC的本质是分布式计算的抽象层

  • 降低复杂度:将网络、序列化、传输等细节透明化
  • 提升效率:避免重复造轮子,聚焦业务逻辑
  • 促进标准化:为微服务、云原生架构奠定基础

如今,RPC已成为分布式系统的基石,从早期的学术构想演变为支撑互联网基础设施的关键技术。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐