前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么我们要改用gRPC

为什么我们要改用gRPC

作者头像
CNCF
发布2019-12-04 15:39:51
2.4K0
发布2019-12-04 15:39:51
举报
文章被收录于专栏:CNCFCNCF

作者:Levin Fritz

当你使用微服务风格的体系结构时,你需要做的一个非常基本的决定是:你的服务如何相互通信?默认的选择似乎是通过HTTP发送JSON — 使用所谓的REST API,尽管大多数人不太重视REST原则。我们在fromAtoB就是这样开始的,但最近我们决定将gRPC作为我们的标准。

gRPC是一个用于远程过程调用的系统,由谷歌开发,现在是开源的。虽然它已经存在好几年了,但是我还没有在网上找到很多关于人们为什么使用或不使用它的信息,所以我决定写一篇文章来解释我们使用gRPC的原因。

gRPC的明显优势是它使用了一种高效的二进制编码,这使得它比JSON/HTTP更快。虽然速度更快总是受欢迎的,但是有两个方面对我们来说更重要:清晰的接口规范和对流的支持。

gRPC接口规范

当你创建一个新的gRPC服务时,第一步总是在.proto文件中定义接口。下面的代码展示了它的样子 — 它是我们自己的API的一小部分的简化版本。该示例定义了单个远程过程调用“Lookup”及其输入和输出类型。

代码语言:javascript
复制
syntax = "proto3";


package fromatob;


// FromAtoB is a simplified version of fromAtoB’s backend API.
service FromAtoB {
  rpc Lookup(LookupRequest) returns (Coordinate) {}
}


// A LookupRequest is a request to look up the coordinates for a city by name.
message LookupRequest {
  string name = 1;
}


// A Coordinate identifies a location on Earth by latitude and longitude.
message Coordinate {
  // Latitude is the degrees latitude of the location, in the range [-90, 90].
  double latitude = 1;


  // Longitude is the degrees longitude of the location, in the range [-180, 180].
  double longitude = 2;
}

使用这个文件,你可以使用protoc编译器生成客户机和服务器代码,并且可以开始编写提供或使用API的代码。

那么,为什么这是一件好事,而不是额外的工作?再看一下上面的代码示例。即使你从未使用过gRPC或协议缓冲区(Protocol Buffers),它非常可读的:例如,很明显,做一个Lookup请求你应该发送一个name,它是一个字string,你会得到一个Coordinate,它包含latitude和longitude。实际上,一旦你添加了一些简单的注释,例如在本例中,.proto文件就是你的服务的API文档。

当然,实际服务的规范可以更大,但不会更复杂。它只是更多的用于方法的rpc语句和用于数据类型的message语句。

由protoc生成的代码还将确保客户机或服务器发送的数据符合规范。这对调试有很大的帮助。我记得有两个实例,其中我正在处理的服务生成的JSON数据格式错误,而且由于该格式没有在任何地方进行验证,因此问题只出现在用户界面中。找出问题的唯一方法是调试JavaScript前端代码 — 如果你是一个从未使用过前端使用的JavaScript框架的后端开发者,那么调试JavaScript前端代码就不那么容易了!

Swagger/OpenAPI

原则上,使用Swagger或它的后续OpenAPI,你可以为HTTP/JSON API获得相同的好处。下面是一个与上面的gRPC API相同的例子:

代码语言:javascript
复制
openapi: 3.0.0


info:
  title: A simplified version of fromAtoB’s backend API
  version: '1.0'


paths:
  /lookup:
    get:
      description: Look up the coordinates for a city by name.
      parameters:
        - in: query
          name: name
          schema:
            type: string
          description: City name.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Coordinate'
        '404':
          description: Not Found
          content:
            text/plain:
              schema:
                type: string


components:
  schemas:
    Coordinate:
      type: object
      description: A Coordinate identifies a location on Earth by latitude and longitude.
      properties:
        latitude:
          type: number
          description: Latitude is the degrees latitude of the location, in the range [-90, 90].
        longitude:
          type: number
          description: Longitude is the degrees longitude of the location, in the range [-180, 180].

将其与上面的gRPC规范进行比较。OpenAPI要难读得多!它更冗长,结构也更复杂(八个缩进级别而不是一个)。

使用OpenAPI规范进行验证也比使用gRPC更加困难。至少对于内部服务,这意味着要么没有编写规范,要么没有更新规范,随着API的发展,这些规范将变得毫无用处。

流处理

今年早些时候,我开始为我们的搜索设计一个新的API(想想“2019年6月1日给我从柏林到巴黎的所有连接”)。在我用HTTP和JSON构建了API的第一个版本之后,我的一个同事指出,在某些情况下,我们需要对结果进行流处理,这意味着我们应该在收到第一个结果时就开始发送它们。我的API只返回了一个JSON数组,所以服务器在收集所有结果之前不能发送任何东西。

我们在前端使用的API中所做的是让客户端轮询结果。它们发送POST请求来设置搜索,然后发送重复的GET请求来检索结果。响应包含一个字段,该字段指示搜索是否完成。这可以很好地工作,但不优雅,并且需要服务器使用诸如Redis之类的数据存储来保存中间结果。新的API将由多个较小的服务实现,我不想强迫它们都实现这个逻辑。

那时我们决定试用gRPC。要用gRPC发送远程过程调用的结果,只需在.proto文件中添加stream关键字。这是我们的Search函数的定义:

代码语言:javascript
复制
rpc Search (SearchRequest) returns (stream Trip) {}

由protoc编译器生成的代码包括一个带有Send函数的对象,服务器代码调用该函数来逐个发送Trip对象,和一个带有Recv函数的对象,客户机代码调用该函数来检索它们。从程序员的角度来看,这比实现轮询API要容易得多。

注意事项

我想提一下gRPC的几个缺点。它们都与工具有关,而不是协议本身。

使用HTTP/JSON构建API时,可以使用curl、httpie或Postman进行简单的手工测试。gRPC也有一个类似的工具,名为grpcurl,但它并不是无缝的:你必须在服务器端添加gRPC服务器反射扩展名,或者在每个命令上指定.proto文件。我们发现在服务器中包含一个小的命令行实用程序更方便,它允许你进行简单的请求。由protoc生成的客户机代码实际上使这变得非常简单。

对我们来说,一个更大的问题是Kubernetes负载平衡器(用于HTTP服务)在gRPC上不能很好地工作。基本上,gRCP需要应用程序级的负载平衡,而不是TCP连接级的负载平衡。为了解决这个问题,我们按照本教程的指导建立了Linkerd:Kubernetes无痛作gRPC负载平衡

https://kubernetes.io/blog/2018/11/07/grpc-load-balancing-on-kubernetes-without-tears/

结论

尽管构建gRPC API需要更多的前期工作,但是我们发现,拥有清晰的API规范和对流的良好支持可以弥补这一点。对于我们来说,gRPC将是我们构建的任何新的内部服务的默认选项。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CNCF 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档