为什么从REST转向gRPC 需要流式传输搜索结果,也就是在有第一批结果时就开始传输
https://mp.weixin.qq.com/s/aEO3Y8SkObNgfQU3z8sH2w
我们为什么从REST转向gRPC
服务间的通信方式是在采用微服务架构时需要做出一个最基本的决策。默认的选项是通过 HTTP 发送 JSON,也就是所谓的 REST API。我们也是从 REST 开始的,但最近我们决定改用 gRPC。
gRPC 是谷歌开发的一个远程调用框架,现在已开源。尽管它已经出现了多年,但网上关于人们为什么要用它或者为什么不用它的信息并不多。于是,我决定写这篇文章分享一下我们为什么要使用 gRPC。
gPRC 的一个很明显的优势是它使用了二进制编码,所以它比 JSON/HTTP 更快。虽然说速度越快越好,但我们也要考虑另外两个因素:清晰的接口规范和对流式传输的支持。
gRPC 的接口规范
创建 gRPC 服务的第一步是在.proto 文件中定义好接口。下面的代码是一个接口的定义,它定义了一个简单的远程过程调用”Lookup“以及相应的输入和输出类型。
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 或提供 API 服务的代码。
那么,为什么说这个接口定义其实不算是额外的工作量反而是件好事?看看上面的代码,即使你之前从来没有使用过 gRPC 或者 Protocol Buffer,也能轻松读懂它。比如,如果要发送一个 Lookup 请求,你需要发送 name 字符串,然后会接收到由 latitude 和 longitude 组成的 Coordinate 对象。实际上,因为你已经在.proto 文件中加入了一些简单的注释,所以它也可以作为服务的 API 文档来使用。
当然,真正的服务定义规范比这个要长得多,但也不会太复杂,只是会多一些用于定义方法的 rpc 语句和一些用于定义数据类型的 message 语句。
通过 protoc 编译器生成的代码可以确保客户端发送或服务器端接收到的数据是遵循规范的,这样非常有助于调试。我记得有两次我开发的服务因为格式没有经过验证而生成了错误的 JSON 数据,这些问题只会在用户界面上表现出来。要想找出问题的根源,我们只能调试前端 JavaScript 代码,而这对于一个不太熟悉 JavaScript 框架的后端开发人员来说这并不容易!
Swagger/OpenAPI
当然,如果使用的是 JSON/HTTP,Swagger 或者 OpenAPI 也提供了类似的东西。下面的例子与上述的 gRPC API 相当。
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 的定义更难懂,也更啰嗦,结构也更复杂(8 层的缩进)。
OpenAPI 的规范验证比 gRPC 要困难一些,至少对于内部服务来说。随着 API 的不断演化,如果不去更新规范,它就会变得毫无用处。
流式传输
今年早些时候,我开始为我们的搜索服务设计一个新的 API。在我使用 JSON/HTTP 设计了第一版 API 之后,我的一个同事告诉我说,在某些情况下,我们需要流式传输搜索结果,也就是在有第一批结果时就开始传输。而我之前设计的 API 只返回一个单独的 JSON 数组,在服务器端收集到所有结果之前是不会向客户端发送任何数据的。
我们的 API 要求客户端轮询搜索结果,先是发送一个 POST 请求发起搜索,然后再不断发送 GET 请求获取搜索结果。响应消息中包含了一个用于表示搜索是否已完成的字段。这种方式虽然没有什么问题,但还不够优雅,而且要求服务器端将中间结果保存在数据存储(如 Redis)中。
这个时候,我们决定试一试 gRPC。要通过 gRPC 发送结果,只需要在.proto 文件中加入 stream 关键字。下面是我们的 Search 函数定义:
rpc Search (SearchRequest) returns (stream Trip) {}
使用 protoc 编译器生成的代码中包含了一个对象,这个对象有一个 Send 函数,我们的服务器端代码将调用这个函数将 Trip 对象一个接一个地发送出去。代码中还包含了一个 Recv 函数,客户端代码通过调用这个函数来接收 Trip 对象。从开发者的角度来看,这比实现轮询 API 要简单得多。
注意事项
gRPC 也有一些不足之处,不过它们都与相关的开发工具有关,并不是 gRPC 本身的问题。
如果我们使用 JSON/HTTP 开发 API,就可以使用 curl、httpie 或者 Postman 进行简单的手动测试。gRPC 也有一个类似的工具叫作 grpcurl,不过它使用起来并不是很方便,你要么需要在服务器端添加 gRPC 服务器反射插件,要么需要在每个命令后面附上.proto 文件。
另一个是 Kubernetes 负载均衡器问题,负载均衡器可以支持 HTTP,但对 gPRC 支持得并不好。gPRC 要求应用层的负载均衡,而不是在 TCP 连接层。为了解决这个问题,我们参考了这篇文章搭建了 Linkerd:
https://kubernetes.io/blog/2018/11/07/grpc-load-balancing-on-kubernetes-without-tears/
结 论
尽管开发 gRPC API 在前期需要做更多的工作,但拥有清晰的 API 定义和对流式传输的支持对我们来说更重要。在构建新的内部服务时,gRPC 将会是我们的首选。
英文原文:
https://eng.fromatob.com/post/2019/05/why-were-switching-to-grpc/
为什么从REST转向gRPC 需要流式传输搜索结果,也就是在有第一批结果时就开始传输的更多相关文章
- 基于grpc的流式方式实现双向通讯(python)
grpc介绍 grpc是谷歌开源的一套基于rpc实现的通讯框架(官网有更完整的定义).在搞懂grpc之前,首先要弄懂rpc是什么.下面是自己理解的rpc定义,若有不对,望指出: rpc官方称为 远程过 ...
- Go gRPC教程-服务端流式RPC(三)
前言 上一篇介绍了简单模式RPC,当数据量大或者需要不断传输数据时候,我们应该使用流式RPC,它允许我们边处理边传输数据.本篇先介绍服务端流式RPC. 服务端流式RPC:客户端发送请求到服务器,拿到一 ...
- Go gRPC教程-客户端流式RPC(四)
前言 上一篇介绍了服务端流式RPC,客户端发送请求到服务器,拿到一个流去读取返回的消息序列. 客户端读取返回的流的数据.本篇将介绍客户端流式RPC. 客户端流式RPC:与服务端流式RPC相反,客户端不 ...
- ASP.NET Core 3.0 gRPC 双向流
目录 ASP.NET Core 3.0 使用gRPC ASP.NET Core 3.0 gRPC 双向流 ASP.NET Core 3.0 gRPC 认证授权 一.前言 在前一文 <ASP.NE ...
- 应答流式RPC 请求流式RPC 向流式RPC 流式RPC的三种具体形式
https://mp.weixin.qq.com/s/pWwSfXl71GQZ3KPmAHE_dA 用Python进行gRPC接口测试(二) 大帆船 搜狗测试 2020-02-07 上期回顾:用P ...
- FunDA(2)- Streaming Data Operation:流式数据操作
在上一集的讨论里我们介绍并实现了强类型返回结果行.使用强类型主要的目的是当我们把后端数据库SQL批次操作搬到内存里转变成数据流式按行操作时能更方便.准确.高效地选定数据字段.在上集讨论示范里我们用集合 ...
- CSS3与页面布局学习笔记(四)——页面布局大全(负边距、双飞翼、多栏、弹性、流式、瀑布流、响应式布局)
一.负边距与浮动布局 1.1.负边距 所谓的负边距就是margin取负值的情况,如margin:-100px,margin:-100%.当一个元素与另一个元素margin取负值时将拉近距离.常见的功能 ...
- PHP流式上传和表单上传(美图秀秀)
最近需要开发一个头像上传的功能,找了很多都需要授权的,后来找到了美图秀秀,功能非常好用. <?php /** * Note:for octet-stream upload * 这个是流式上传PH ...
- Vue2.0流式渲染中文乱码问题
在参照vue2.0中文官方文档学习服务端渲染之流式渲染时,因为响应头默认编码类型为GBK,而文件为UFT-8类型,所以出现了中文乱码问题. 解决办法:设置响应头编码类型即可 response.setH ...
随机推荐
- EF5中使用UnitOfWork
前言 每次提交数据库都会打开一个连接,造成结果是:多个连接无法共用一个数据库级别的事务,也就无法保证数据的原子性.一致性. 解决办法是:在ObjectContext的CRUD操作基础上再包装一层,提供 ...
- python的常量与变量
1.Python属于强类型编程语言,Python解释器会根据赋值或运算来自动判断变量的类型.Python还是一种动态类型语言,变量的类型也是可以随时变化的. >>> x=3 > ...
- Argo CD使用指南:如何构建一套完整的GitOps?
随着Kubernetes继续将自己确立为容器编排的行业标准,为你的应用和工具找到使用声明式模型的有效方法是成功的关键.在这篇文章中,我们将在AWS中建立一个K3s Kubernetes集群,然后使用A ...
- 深入理解CSS盒模型【转载】
下面本文章将会从以下几个方面谈谈盒模型. 基本概念:标准模型 和IE模型 CSS如何设置这两种模型 JS如何设置获取盒模型对应的宽和高 实例题(根据盒模型解释边距重叠) BFC(边距重叠解决方案) 基 ...
- 解决npm ERR!
一:[Unexpected end of JSON input while parsing near]报错 最近的vue项目中在执行 npm install 时会报错误: npm ERR! Unexp ...
- Linux 时间同步 04 ntp时间同步
Linux 时间同步 04 ntp时间同步 目录 Linux 时间同步 04 ntp时间同步 安装ntp 配置与外部时间服务器进行时间同步的客户端主机 配置其他客户端与以上客户端主机时间同步 验证查看 ...
- eclips如何安装jetty插件
转载自http://www.cnblogs.com/nightswatch/p/4639687.html的博文 eclipse中安装jetty插件并使用 一.eclipse中jetty插件安装: ...
- 手撕redis分布式锁,隔壁张小帅都看懂了!
前言 上一篇老猫和小伙伴们分享了为什么要使用分布式锁以及分布式锁的实现思路原理,目前我们主要采用第三方的组件作为分布式锁的工具.上一篇运用了Mysql中的select ...for update实现了 ...
- 阿里面试:MySQL如何设计索引更高效?
有情怀,有干货,微信搜索[三太子敖丙]关注这个不一样的程序员. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的系列文章. ...
- Spring Boot 2.x基础教程:使用Flyway管理数据库版本
之前已经介绍了很多在Spring Boot中使用MySQL的案例,包含了Spring Boot最原始的JdbcTemplate.Spring Data JPA以及我们国内最常用的MyBatis.同时, ...