我们今天的客座文章来自 CoreOS 的 Brandon Phillips。 CoreOS 为 Linux 容器构建开源项目和产品。他们用于共识和发现的旗舰产品 (etcd) 以及他们的容器引擎 rkt 是 gRPC 的早期采用者,gRPC 是一个基于 protobufs 和 HTTP/2 的 RPC 框架,可以使构建和使用 API 更轻松,性能更高。由于许多客户端使用 http/1.1 加上 json,因此与 JSON 和 Open API 的互操作性非常重要。对于更习惯于 HTTP/1.1+JSON 驱动的 API 和 Open API Initiative 规范(以前称为 swagger)API 的用户,他们正在使用组合开源库来以这种形式提供他们的 gRPC 服务。他们已经构建了 API 多路复用器,为用户提供两全其美的方法。让我们深入了解细节,看看他们是如何做到的!
这篇文章最初发表在 CoreOS 博客 (链接)。我们在此转载,并进行了部分编辑。
CoreOS 选择 gRPC 的关键原因之一是它使用 HTTP/2,使应用程序能够在一个 TCP 端口上同时提供 HTTP 1.1 REST+JSON API 和高效的 gRPC 接口。(适用于 Go)这使开发人员能够与 REST 网络生态系统兼容,同时推进一种新的、高效率的 RPC 协议。随着 Go 1.6 最近发布,Go 默认情况下附带了一个稳定的 net/http2 包。
一个名为 EchoService 的 gRPC 应用程序
在这篇文章中,我们将从 gRPC API 定义构建一个小型的概念验证 gRPC 应用程序,添加 REST 服务网关,最后将它们全部提供在一个 TLS 端口上。该应用程序称为 EchoService,是 shell 命令 echo 的网络等效项:该服务将返回或“回显”发送给它的任何文本。
首先,让我们在一个名为 EchoMessage 的 protobuf 消息中定义 EchoService 的参数,其中包含一个名为 value 的字段。我们将在一个名为 service.proto 的 protobuf“.proto”文件中定义此消息。这是我们的 EchoMessage
message EchoMessage { string value = 1; }
在同一个 protobuf 文件中,我们定义了一个 gRPC 服务,它接收此数据结构并返回它
service EchoService { rpc Echo(EchoMessage) returns (EchoMessage) { } }
将此 service.proto 文件通过 Protocol Buffer 编译器 protoc 运行,将在 Go 中生成一个存根 gRPC 服务,以及各种语言的客户端。但是 gRPC 本身不像一个也暴露 REST 接口的服务那样有用,因此我们不会止步于 gRPC 服务存根。
接下来,我们添加 gRPC REST 网关。此库将在 gRPC EchoService 之上构建一个 RESTful 代理。要构建此网关,我们在 EchoService proto 中添加元数据,指示 Echo RPC 映射到一个 RESTful POST 方法,并将所有 RPC 参数映射到一个 JSON 主体。网关可以将 RPC 参数映射到 URL 路径和查询参数,但为了简洁起见,这里省略了这些复杂情况。
service EchoService { rpc Echo(EchoMessage) returns (EchoMessage) { option (google.api.http) = { post: “/v1/echo” body: “*” }; } }
实际上,这意味着网关在由 protoc 生成后,现在可以接受来自 curl 的类似以下请求。
curl -X POST -k https://localhost:10000/v1/echo -d ‘{“value”: “CoreOS is hiring!”}’
到目前为止,整个系统看起来像这样,只有一个 service.proto 文件生成 gRPC 服务器和 REST 代理。
带有 REST 网关的 gRPC API
为了将所有这些整合在一起,echo 服务创建了一个 Go http.Handler 来检测协议是否为 HTTP/2 以及 Content-Type 是否为“application/grpc”,并将此类请求发送到 gRPC 服务器。其他所有内容都路由到 REST 网关。代码看起来像这样。
if r.ProtoMajor == 2 && strings.Contains(r.Header.Get(“Content-Type”), “application/grpc”) { grpcServer.ServeHTTP(w, r) } else { otherHandler.ServeHTTP(w, r) }
要试用它,您只需要一个 可用的 Go 1.6 开发环境 以及以下简单的咒语。
$ go get -u github.com/philips/grpc-gateway-example $ grpc-gateway-example serve
服务器运行后,您可以在 HTTP 1.1 和 gRPC 接口上尝试请求。
grpc-gateway-example echo 使用 gRPC 从 REST 中休息一下 curl -X POST -k https://localhost:10000/v1/echo -d ‘{“value”: “CoreOS is hiring!”}’
最后一个好处:因为我们有 Open API 规范,所以您可以浏览 Open API UI,它运行在 https://localhost:10000/swagger-ui/#!/EchoService/Echo(如果您在笔记本电脑上运行了上面的服务器)。
gRPC/REST Open API 文档
我们已经了解了如何使用 gRPC 连接到 REST 世界。如果您想查看完整项目,请查看 GitHub 上的仓库。我们认为使用单个 protobuf 来描述 API 的这种模式可以带来易于使用、灵活的 API 框架,我们很高兴在更多项目中利用它。
—
关于作者
Brandon Phillips (CoreOS)
Brandon Philips 作为 CTO,正在帮助 CoreOS 构建现代的 Linux 服务器基础设施。在加入 CoreOS 之前,他在 Rackspace 从事云监控工作,并在 SUSE 担任 Linux 内核开发人员。作为俄勒冈州立大学开源实验室的毕业生,他对开源技术充满热情。