一个用于构建浏览器和gRPC兼容的HTTP API的瘦身库

596 阅读6分钟

今天我们发布了Connect,一个用于构建浏览器和gRPC兼容的HTTP API的纤细框架。Connect是为生产准备的--专注、简单、可调试--并且它与gRPC客户端和服务器完全兼容。如果你对今天的gRPC库的复杂性和不稳定性感到沮丧,我们认为你会发现Connect是一股新鲜空气。**Connect-go现在可以在Apache 2开源许可下使用,文档可以在connect.build**上找到。我们将很快发布Connect for TypeScript,更多的语言将陆续发布。

另一个RPC框架?

在其发布后的七年里,gRPC为Protobuf RPC带来了亟需的共识。从一个相互竞争、互不兼容的业余项目开始,gRPC团队将社区团结在一个共同的协议周围,向许多开发者介绍了RPC风格的API,并推动了Protobuf在谷歌之外的普及。由于他们的不懈努力,我们可以用Protobuf指定我们的API,用gRPC实现它们,并确信大多数语言都会有一个兼容的客户端库。

从概念上讲,gRPC协议是带有Protobuf编码的体的HTTP,并洒上了元数据。尽管有这个简单的前提,但该协议和今天的gRPC库都有一个最大限度的设计理念,导致了非凡的复杂性。gRPC非但没有使生产系统变得简单和稳定,反而使开发、部署、调试和维护过度复杂化。

作为一个例子,考虑谷歌在Go中的gRPC实现。

  • 除去注释,grpc-go 是13万行手写的代码。它有几十个子包,近百个配置选项,以及定制的名称解析和负载平衡机制。仅仅筛选这些功能的厨房水槽就需要几个小时,而且代码的数量之大使得细微的错误和资源泄漏不可避免。
  • grpc-go 没有使用Go标准库的net/http ,而是使用自己的HTTP/2实现。它与Go的HTTP生态系统的其他部分不兼容,所以你不能干净地将gRPC请求与其他HTTP流量一起提供,也不能使用大多数第三方包。
  • gRPC协议需要对HTTP/2和拖车的端到端支持。支持常见的HTTP客户端--如网络浏览器--需要精心设计的翻译代理。
  • 除了使用晦涩的HTTP特性外,gRPC协议还很难调试。即使启用了JSON支持,简单的请求-响应RPC也会将你关心的JSON与二进制框架数据混合在一起。忘了curl | jq 或Chrome网络检查器吧--现有的工具都是不成熟的,而且是针对gRPC的。
  • 作为一项政策,grpc-go不遵循语义版本;发布说明甚至包括一个专门的 "行为变化 "部分。在过去的一年中,至少有四个版本破坏了向后的兼容性,著名的gRPC用户(包括etcd)往往在几个月内都无法更新。

平衡grpc-go"的开源社区和谷歌内部用户的需求是一项困难和不容易的任务。而且,也许它的功能和选项的广度是谷歌内部需要采用的。对于我们其他人来说,grpc-go 的复杂性和不稳定性代表了我们核心业务的不愉快的分心。

生产级的简单性

Connect为Protobuf驱动的API带来了简单性。每一个Connect的实现都是集中的:只有基本的功能,建立在经过时间考验的HTTP库之上,并被设计为不影响你的工作。

  • 在Go中,Connect只是一个包,只有几千行代码和少数几个常用的选项。即使是生成的代码也是为了让人阅读。

  • 它是建立在net/http 。Connect处理程序实现了http.Handler ,而Connect客户端则包裹了http.Client 。它们与任何第三方路由器、中间件或服务器一起工作。

  • net/http 的基础上,connect-go 支持三种RPC协议:gRPC、gRPC-Web和Connect自己的协议。处理程序默认支持这三种协议,而客户端可以通过一个配置选项来切换协议--不需要改变其他代码。

  • 连接协议是一个简单的、仅有POST的协议,通过HTTP/1.1或HTTP/2工作。它吸收了gRPC和gRPC-Web的最佳部分,包括流媒体,并将其打包成一个协议,在浏览器、单体和微服务中同样适用。Connect协议是我们认为gRPC协议应该有的样子。默认情况下,支持JSON-和二进制编码的Protobuf。调用Connect API就像使用curl 一样简单。

    # Try it out! This is a live demo!
    curl \
        --header "Content-Type: application/json" \
        --data '{"sentence": "I feel happy."}' \
        https://demo.connect.build/buf.connect.demo.eliza.v1.ElizaService/Say
    
  • connect-go 也支持完整的gRPC协议,包括流媒体、头文件、拖车和错误细节。gRPC兼容的服务器反射健康检查可以作为独立的软件包使用。代替cURL,我们可以用以下方式调用我们的Connect API [grpcurl](https://github.com/fullstorydev/grpcurl):

    # This is also a live demo!
    go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
    grpcurl \
        -d '{"sentence": "I feel happy."}' \
        demo.connect.build:443 \
        buf.connect.demo.eliza.v1.ElizaService/Say
    
  • 处理程序和客户端也支持gRPC-Web协议,因此浏览器可以直接连接到你的服务器。我们使用谷歌自己的互操作性测试的扩展版本来验证我们的gRPC和gRPC-Web实现。

  • 头文件、预告片和其他元数据都是明确传递的,而不需要将任何东西附加到Go上下文中。通过泛型,所产生的代码是符合人体工程学的,类型安全的,并且易于推理。

如果你使用过Buf CLI或Schema Registry,你就使用过Connect - 在内部,我们已经用connect-go 完全取代了grpc-go 。我们发现Connect在生产中是一种乐趣:它很小,很简单,而且可以调试。

在Go中,Connect目前处于测试阶段:我们在生产中依靠它,但我们可能会在收集早期采用者的反馈时做一些改变。我们计划在十月给稳定的v1.0 ,在Go 1.19发布后不久。我们非常重视语义上的版本管理:一旦我们发布v1.0 ,我们就不会破坏你的构建。

即将发布

我们对Connect生态系统有很大的计划!除了Go中的Connect,我们一直在为浏览器开发TypeScript的实现。它具有相同的设计优先级:它一路都是成语式的TypeScript,接近浏览器的获取API,整齐地适合React钩子,并支持gRPC-Web和Connect自己的协议。它还能产生微小的捆绑。我们已经在Buf Schema Registry前端替换了grpc-web ,并且我们计划很快发布connect-web ,敬请关注。

最终,我们希望为Express、Rails、Django、Laravel和类似的框架发布Connect的实现。你不应该在这些富有成效的工具包和协议缓冲器之间做出选择--它们应该无缝地结合起来。

请参与进来

我们很想听听你对Connect的看法:看看入门指南,在你的下一个Go项目中尝试Connect,探究一下示范项目,如果有什么地方不符合你的期望,请提出问题。我们在Buf Slack中随时待命,而且我们通常也在Gophers Slack的#grpc和#connect频道中。