人工智能正在改变人与计算机的交互方式,而语音正成为这一变革中日益重要的组成部分。实时助手、AI 驱动的听写以及其他语音接口,都需要客户端、模型和支撑服务之间的低延迟通信。许多开发者使用 gRPC——一种构建在 HTTP/2 和 TCP 之上的远程过程调用(RPC)框架——来搭建这类基础设施。
自从 Workers 于 2017 年推出以来,我们一直在扩展其能力,包括增加发起出站 TCP 连接的能力,以及一个基于 Cap'n Proto 构建的 JavaScript 原生 RPC 系统。因此,作为 Agents Week 的一部分,我们正从另一个方向扩展 Workers,支持入站 TCP 连接,并新增了在 Cloudflare 上运行 gRPC 应用的方式。
今天,我们宣布:
- connect(socket)——Workers 运行时中的一个新处理器,让你的 Worker 能够直接接受由 Spectrum(Cloudflare 面向非 HTTP 流量的入站代理)提供的入站 TCP 套接字。
- 来自 Cloudflare Containers 的全双工、双向 gRPC——将套接字从你的 Worker 转发到运行在容器中的 gRPC 服务器。
- Workers 可以服务一元(unary)和服务器流式(server-streaming)gRPC API,并调用 gRPC 服务器——你使用 gRPC-web 编写代码,Cloudflare 会自动将入站和出站请求转换为 gRPC。
我们正以私有测试版(private beta)形式推出这一功能——你可以在此处注册。
下面我们来逐一深入介绍。
从你的 Worker 到 Durable Objects 和 Containers 的 connect(socket)
Workers 运行时现在提供了一个 connect() 处理器,用于接受一个你可以读取和写入的套接字:
你可以将这个套接字从一个 Worker 传递给另一个 Worker,或从一个 Worker 传递给一个 Durable Object。这让你能够控制入站 TCP 连接的路由去向:
你可以将套接字从 Durable Object 传递给其 Container:
然后在容器中处理该套接字:
这让你能够完全掌控从客户端到运行在 Cloudflare 容器中服务器的整个路径,为客户端与运行任意程序、使用任意语言、基于任意 TCP 协议的服务器之间的全双工通信打开了大门。
为了向客户端暴露原始 TCP 套接字,我们推出了一种新型 Spectrum 应用,你可以指定一个 Worker,将传入的 TCP 连接路由到该 Worker。Spectrum 是 Cloudflare 面向非 HTTP 流量的入站代理,它让 Cloudflare 能够部署在任何 TCP 或 UDP 应用的前端。
来自 Cloudflare Containers 的双向 gRPC
gRPC 是一种成熟且广受欢迎的远程过程调用(RPC)框架,最初由 Google 在近 10 年前发布,如今已广泛应用于移动应用、分布式系统,以及最近兴起的——语音 AI 应用。
实时语音 AI 应用要求低延迟,并且客户端和服务器需要能够通过单一、持久的连接相互发送消息。WebSockets 和 Durable Objects 非常适合这一场景,Cloudflare Agents SDK 提供了 @cloudflare/voice 来简化这一过程。但市面上有大量软件使用 gRPC 进行实时客户端-服务器通信。
利用上述 API,你现在可以将用任何语言编写的 gRPC 服务器部署到 Cloudflare,并完全支持客户端与服务器之间的双向流式传输。这让你能够利用 Cloudflare 覆盖 330 多个地点的网络,在比其他任何地方都更靠近客户端的位置处理请求。我们对这为低延迟语音和同地推理所开辟的可能性感到非常兴奋。
例如,下面是一个极简的 gRPC 服务器,它会将收到的消息回显给客户端:
有了这个,几乎没有任何基于 gRPC 的应用是你无法部署到 Cloudflare 的,无论它使用什么语言或依赖什么库。但如果你需要做一些更简单的事情,比如只是运行一个基础的 gRPC 服务器,或者从 Worker 连接到运行在其他地方的 gRPC 服务器,那该怎么办?
Workers 作为 gRPC 服务器和客户端,支持 gRPC 到 gRPC-web 的转换——无需容器
gRPC-web 是 gRPC 的浏览器兼容版本。Web 浏览器不暴露 gRPC 所需的底层 HTTP/2 特性,而且浏览器中也没有内置的原始 TCP 套接字 API——这正是 WebSocket API 存在的原因,也是 Workers 自 2021 年起就支持 WebSockets 的原因。
HTTP/2 会将每个请求和响应拆分成称为帧的小型二进制消息。这是单个 HTTP/2 或 HTTP/3 连接能够实现多路复用的核心机制——多个请求可以在同一条连接上交错传输。每个帧都带有流 ID,使接收方能够将其重新组装成正确的请求或响应。gRPC 依赖这种流级控制来实现高效的流式传输、取消、流量控制和尾部元数据。
fetch() 等 Web 平台 API 并不提供这种控制能力。那么,我们如何让在 Cloudflare Workers 中使用 gRPC 变得简单易用——同时客户端无需做任何更改?我们将传入的 gRPC 转换为 gRPC-web,并将传出的 gRPC-web 转换为 gRPC。
实际上,自 2020 年以来,我们一直在 Cloudflare 的反向代理中使用 gRPC-web,当时我们在 Cloudflare 博客上发表了关于 gRPC 之路的文章。我们将请求转换为 HTTP/1.1,以便能够检查消息,并让 gRPC 应用受益于 Cloudflare 的安全功能,例如 WAF 规则和 Bot Management。
现在,在私有测试版之后将向所有人推出,我们正在扩展这一功能,使得在给定如下所示的 Protocol Buffer(protobuf)定义文件时:
您可以使用 @connectrpc/connect 开源包,仅用几行代码即可在 Worker 中编写一个一元 gRPC 服务器:
您也可以通过使用 @connectrpc/connect 内置的客户端,以这种方式向外部 gRPC 服务器发出出站请求:
您的代码使用 gRPC-web,但当它与外部世界通信时,会自动转换为 gRPC。这意味着您已经依赖的客户端和服务器无需更改。例如,您可以:
- 为使用 gRPC 的移动应用提供 gRPC 后端——许多移动应用已经使用 gRPC 来减少网络负载、更高效地序列化数据,并生成强类型客户端库。您现在可以在 Workers 上为移动应用构建后端服务器,同时仍然使用成熟的 gRPC 原生库,例如 grpc-swift-2 和 grpc-kotlin。
- 在现有 gRPC 后端前放置一个 Worker——许多开发者已经将 Worker 置于现有 REST API 之前,以便将性能关键型工作迁移到更靠近用户的位置,或逐步将状态迁移到 Durable Objects。现在,你也可以对现有的 gRPC 后端执行同样的操作,或者构建新的 API 和服务,从现有的 gRPC 后端获取数据。
Cloudflare 上 Socket Workers 和 gRPC 的下一步计划
我们将在私有测试版中推出本文介绍的所有内容——你可以在此处注册。
在 Cloudflare,我们使用 Cap'n Proto、Cap'n Web 以及内置于 Cloudflare Workers 的 JavaScript 原生 RPC 系统,而不是 gRPC。当我们发布产品时,我们总是力求自己先使用它们。因此,在这种情况下,我们希望首先与一小部分使用 gRPC 的开发者密切合作,确保我们做得尽善尽美,然后再向所有人开放。
更广泛地说,我们很高兴能继续突破 Workers 平台可承载的流量类型的界限,超越 TCP,进入基于 UDP 的协议。请继续告诉我们你想在 Workers 上构建什么,我们将继续突破可能性的边界。