【问题标题】:When is an API not RPC?什么时候 API 不是 RPC?
【发布时间】:2017-05-22 10:41:55
【问题描述】:

API 什么时候 RPC?

在 Twitter 上关于 API 设计的长时间讨论之后。 当 API 基于 RPC 时,我想尝试得出一个明确的答案。

这个Is That REST API Really RPC? Roy Fielding Seems to Think So似乎有点混乱

该特定链接是关于 REST 和 RPC 的。我的问题只是想问关于 RPC 与不是 RPC 的一般情况,而不是在 HTTP 的上下文中。

TLDR; API IS RPC 何时为 “当它对开发者隐藏网络时”的定义 很公平。

但回到什么时候不是。

Twitter 讨论集中在 HttpClient,因为它不是 RPC。

我的论点是 HttpClient 并没有真正为网络建模。 那里没有任何建模延迟。 网络故障的表现也很弱。 HTTP 中的大多数状态代码与网络无关,例如未找到、需要付款等。

根据语言和 SDK,HttpClient 可能采用字符串或 URI。 如果它需要一个代表 URI 的字符串,这也不能真正传达涉及网络的信息,您需要知道该字符串代表什么以及 URI 是什么。

如果您以前从未见过 HTTP,那么通过查看特定的 API 怎么知道? 有一个 API 使用一个字符串,并返回一个包含字符串或一些 int 响应代码的对象。

你怎么知道?

当然,大多数开发人员都知道 HTTP 是什么,但从严格定义的角度来看,您如何将 API 定义为不是 RPC?

Java“NetworkException”中的已检查异常是否足以清楚地传达涉及网络的信息? 如果您调用的函数具有诸如“SayHelloOverNetwork”之类的描述性名称,是否足以使其不是 RPC?

究竟什么时候一个过程是远程的过程? 所有网络通信都会导致一些代码在接收系统上运行。

如果我们让一个从未接触过技术或协议的人,教这个人一门编程语言。 这个人可以使用“非 RPC”的定义来识别什么是 RPC 而不是什么?

我在这里很密集,可能很傻,但我试图找到“非 RPC”的本质,这究竟需要什么?

它是否需要例如非阻塞才能在未知延迟下正常运行? 或者非 RPC API 会阻塞吗? IMO,如果它是阻塞的,它隐藏了会涉及延迟,因此陷入“延迟为零”的谬论,意味着它隐藏了网络。

这一切似乎对除我之外的其他所有人来说都非常明显,但还没有人给出关于不成为 RPC 的要求的简明答案。

【问题讨论】:

  • 看看windows API - 它不是 RPC,尽管它使您可以通过自己的协议(非基于 http)调用远程过程
  • 您提到的大多数标准与 RPC 无关。看看 CORBA 和 Sun-RPC。 RPC的本质是,err,Remote Procedure Call。对远程主机的过程调用语义。与延迟网络建模无关,......它应该对你隐藏所有这些。您的问题似乎主要基于您自己对 RPC 是什么的看法,这是错误的。
  • 问题是什么不是 RPC,也就是说,如果 RPC 应该对你隐藏网络语义,那么不是 RPC 的 API 应该是相反的,即明确的网络语义。没有?
  • @RogerAlsing 不,它将是非远程的,即本地的,或者具有非过程调用语义。
  • @EJP 这仍然是个问题,“非过程调用语义”看起来如何?调用 httpClient.Get(...) 如果您在查看特定 API 时不了解 HTTP,您怎么知道那不是另一端称为“Get”的远程过程?

标签: api network-programming rpc distributed-computing


【解决方案1】:

对我来说,你好像把所有的鸡蛋都放在一个篮子里。让我们从头开始:

APIapplication programming interface

它是一组明确定义的各种软件组件之间的通信方法

API 唯一确定的属性是它是定义/记录的通信方式

如果一个应用程序/模块/组件 A 可以以某种方式使用/调用另一个应用程序/模块/组件 B - 这意味着 B 提供 API 而 A 使用此 API。

通常需要定义 API 的两个方面:

  1. 传递到组件/从组件返回的具体内容(它是您的应用程序逻辑)
  2. 数据传输/序列化的准确方式(这是技术实现)

出于显而易见的原因,我没有触及“什么”部分。

让我们专注于“如何”的不同方式:

  • 将 4 字节整数压入堆栈,更改 IP 寄存器并从 EAX 寄存器读取 4 字节整数输出
  • 连接到套接字,将数据序列化为字节数组并将一些响应作为字节数组读回
  • 用任何电话拨打 911,说出您的地址,预计车道上有几辆车

在所有这些情况下,您都在使用一些 API = 您正在以某种预定义的方式与其他组件进行通信。

RPCremote procedure call

计算机程序使过程(子程序)在另一个地址空间中执行

RPC 唯一确定的属性是数据跨不同/远程地址空间传递,某些架构允许单个主机上的不同地址空间,例如 x86。只要不同的物理主机通常不共享地址空间,任何跨网络的调用都是 RPC,反之则不然。

注意:这种情况很少见,但可以在网络中连接的不同物理主机之间共享内存空间——那么这种通信严格来说不是 RPC,让我们省略这种情况。

任何 RPC 调用都自动意味着您正在调用某个 API。根据定义。所以我们可以说RPC 是API“如何”的一部分,它是传输层。只要 RPC 本身没有定义实际的机制,就可能会有非常不同的实现,例如共享内存、DMA、TCP/IP 等。

我想现在你可以回答你的问题when an API is not RPC based - 当 API 这么说的时候。是否应该/是否可以通过 RPC 调用由 API 开发人员定义,API 可以定义多种调用方式。

作为 RPC 的反义词,您可以使用“in-process”。

所以,短语API IS RPC is "when it hides the network from the developer" 绝对是无意义的。 API 必须定义“how”部分。

HTTPhyper text transfer protocol

客户端-服务器计算模型中的请求-响应协议

HTTP 唯一确定的属性是它描述了请求(输入参数)和响应的协议/格式。

您可以在非 RPC API 中使用 HTTP。例如,我更喜欢将 HTTP 视为文件格式。所以我们可以说HTTP 是API“如何”的另一部分。它定义了 API 的序列化部分,但并不规定您的传输级别。

注意:一些 RPC 协议实际上同时定义了传输和序列化。

所以,HttpClient 是允许您调用 API 并使用 HTTP 编码的请求/响应的工具,通常此类库假设 RPC 作为传输层。这些条款都没有强制要求网络或任何特定的传输协议。这就是为什么 http 客户端不应声明任何类型的网络异常/错误,但它可能会将 HTTP 错误作为异常抛出。

注意:网络异常可能会从 TCP/IP RPC 实现中抛出,例如,HTTP 客户端库可以将它们代理给您。不幸的是,一些库错误地将 HTTP 与 TCP/IP 耦合太多,并且跨越了不同职责之间的界限。

RESTrepresentational state transfer

分布式超媒体系统的架构风格

这是一个非常广泛的术语,它从不同的方面和不同的层面定义了很多东西,最重要的是:

  • 如何设计您的 API(URI 的使用)
  • 如何实现您的 API(无状态、HTTP 动词)
  • 如何调用您的 API(客户端-服务器)

客户端-服务器,通常假设跨进程通信。即不同的地址空间,这就是为什么我们可以说 REST 要求 RPC 作为 API + HTTP 作为序列化格式的调用机制。


现在,我想您将能够理解这些答案:

你怎么知道?

当您向客户提供 REST API 时,它会根据其他协议自动定义您的 API 的某些部分。即 - 要使用 REST API,您必须首先阅读/了解 HTTP 协议。 API 必须定义必须使用哪种类型的 RPC。

HttpClient 并没有真正为网络建模。

它不应该这样做。它适用于 HTTP 语义。

你需要知道字符串代表什么并且需要一个 URI

实际上有两个 URI:

  • URI 是 API 的“内容”部分的一部分,它定义了业务对象的位置。它与网络或DNS系统无关。你不应该理解它。
  • URI 可以是 TCP/IP RPC 要求的一部分,在这种情况下,它代表域名/路径。但有些实现可以使用 IP 地址,而不是 URI。

如果您调用的函数具有诸如“SayHelloOverNetwork”之类的描述性名称,是否足以使其不是 RPC?

正如我之前写的 - 我们可以假设网络总是 RPC。

它是否需要例如非阻塞才能在未知延迟下正常运行?

这取决于 API 开发人员:

  1. API 可以包含假设异步执行的函数,但客户端可以以阻塞方式调用它们
  2. API 可以包含阻塞函数,但客户端可以异步调用它们

【讨论】:

    【解决方案2】:

    RPC 是一种网络 API,顶部有足够多的抽象层。什么是足够层?这是主观的事情。

    在我看来,API 是否是 RPC 并不取决于方法名称或您需要处理的异常/错误的名称。我们是成年人,我们知道通话是通过网络完成的。将其命名为“SayHello”而不是“SayHelloOverNetwork”并没有什么不同。

    真正重要的是所有这些抽象层 - 您需要做的资源管理和错误处理越少,代码就越 RPC-ish。

    关于具体的 HttpClient 示例——我想说的是,今天,从事高级工作的开发人员认为 HTTP 是一种传输介质; “普通旧插座”的替代品。

    因此,虽然不知道 HTTP 是什么的人可能会将“接受字符串并返回错误代码的函数”视为 RPC,但现代开发人员可能会将其视为“基本的网络代码”。然后他会说 yuck,并在顶部添加更多抽象层,以使来自他的业务逻辑的方法调用更加 RPC-ish。这样一来,业务逻辑就必须只处理最极端的故障。

    【讨论】:

      【解决方案3】:

      A) 如果文档告诉您如何通过调用 API 来做您想做的事,那么您调用的是类似 RPC 的 API,而不是 REST API。

      B) 如果 API 本身告诉你如何调用它来完成你想要的,那么这个 API 不是很像 RPC,可能是一个 REST API。

      面向对象或过程风格的编程类似于案例 (A) —— 在编写调用它的代码之前,您知道要调用什么以及如何调用它来完成您想要的事情。当 [我假设 Roy F.] 说类似 RPC 的 API 对开发人员隐藏网络时,他的意思是开发人员可以继续以这种方式编程,无论他的调用是否是远程的——他不必关心关于网络。

      但是,当您调用 REST API 时,您必须进行不同的编程,因为您必须让 API 告诉您可以做什么以及如何做。这就是“超文本驱动”的含义。

      超文本驱动意味着当网络另一端的人完全不知道或不关心您的程序时,您的东西将继续工作,完全改变了您可以做什么以及您必须做什么做。请注意,您和您调用的系统之间没有任何合约是 RPC 隐藏的网络的基本特征。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-15
        • 1970-01-01
        • 2011-05-06
        • 2017-08-04
        • 2021-11-29
        • 1970-01-01
        • 2011-09-06
        • 1970-01-01
        相关资源
        最近更新 更多