RSS

为什么我们决定将 API 迁移到 gRPC

Vendasta 八年前作为一家针对小型企业的点解决方案产品提供商起步。从一开始,我们就与拥有大量销售人员并与这些企业建立现有关系的媒体公司和代理商合作,销售我们的软件。据估计,仅在美国就有超过 3000 万家小型企业,因此我们的 SaaS 解决方案的可伸缩性从一开始就被视为我们最关注的问题之一,这也是我们最初选择 Google App Engine 和 Datastore 的原因。当我们的系统从数百个最终用户扩展到数十万个最终用户时,这个解决方案对我们非常有效。在此期间,我们还将我们的产品从点解决方案扩展到包含多个产品和供合作伙伴管理其产品销售的工具的整个平台。

在整个发展过程中,Python GAE 很好地满足了我们的需求。我们通过 HTTP + JSON 公开了许多 API,供我们的合作伙伴自动化任务并将其其他系统与我们的产品和平台集成。然而,在 2016 年,我们推出了 Vendasta Marketplace。这标志着我们的产品发生了重大变化,它在很大程度上依赖于第三方供应商使用我们的 API 在我们的平台上交付他们自己的产品。这是一个重大变化,因为我们的公共 API 为第三方应用程序提供了上限,并使我们意识到,我们确实需要构建卓越而非仅仅够用的 API。

我们开始进行的第一个优化是使用 Go 编程语言构建端点,以实现比使用 Python 更高的吞吐量和更低的延迟。在某些 API 上,这带来了惊人的差异:我们看到 50th 百分位响应时间从 1200 毫秒降至 4 毫秒,更令人惊叹的是 99th 百分位响应时间从 30,000 毫秒降至 12 毫秒!在其他 API 上,我们看到了小得多但仍然显著的差异。

我们使用的第二个优化是将我们 Datastore 数据的大部分复制到 ElasticSearch 中。ElasticSearch 是一种与 Datastore 根本不同的存储技术,而且不是托管服务,所以对我们来说是一个很大的飞跃。但这一改变使我们能够将几乎所有夜间批处理 API 迁移到实时 API。我们尝试过 BigQuery,但其查询处理时间意味着我们无法实时显示内容。我们尝试过 cloudSQL,但数据量太大,难以轻松扩展。我们尝试过 appengine Search API,但它在结果集超过 10,000 条时存在限制。我们转而使用 Google Container Engine 扩展了我们的 ElasticSearch 集群,凭借其强大的聚合和 facet 处理能力,我们的需求得到了轻松满足。因此,通过这两个解决方案的到位,我们对 API 的性能进行了有意义的改变。

我们进行的最后一个优化是将我们的 API 迁移到 gRPC。这一改变比其他改变更广泛,因为它影响到我们的客户端。与 ElasticSearch 一样,它代表了一种具有不同性能特征的根本不同的模型,但与 ElasticSearch 不同的是,我们发现它是一个真正的超集(superset):我们所有的使用场景都受到了积极影响。

我们从 gRPC 中看到的第一个好处是能够从发布 API 并要求开发者与之集成,转变为发布 SDK 并要求开发者复制粘贴用他们语言编写的示例代码。这对于希望与我们产品集成的用户来说是一个巨大的好处,同时也不要求我们为合作伙伴和供应商使用的 5 种以上语言手动编写完整的 SDK。需要注意的是,我们仍然在生成的 gRPC SDK 之上编写轻量级包装器,以使其对包管理器友好,并为生成的 protobuf 结构提供包装器。

我们从 gRPC 中看到的第二个好处是能够摆脱 HTTP + JSON 所必需的请求-响应架构。gRPC 构建在 HTTP/2 之上,HTTP/2 允许客户端流和/或服务器端流。在我们的用例中,这意味着通过在服务器上结果就绪时进行流式传输(服务器端流),我们可以缩短首次显示时间。我们还在研究提供非常灵活的创建端点的潜力,这些端点可以轻松支持批量摄入(bulk ingestion)并支持双向流,这意味着我们将允许客户端异步流式传输结果,同时服务器可以流回状态,从而实现轻松的检查点操作,而不会减慢上传速度来等待确认。我们认为我们才刚刚开始看到这一功能的好处,因为它为客户端-服务器交互开辟了一种在 HTTP 中根本不可能实现全新模型。

第三个好处是从 JSON 切换到 Protocol Buffers,这与 gRPC 配合得非常好。这改进了序列化和反序列化时间;这对于我们某些 API 来说非常重要,但对所有 API 都很有益。更重要的好处来自于 proto 显式的格式规范,这意味着客户端接收的是类型化对象,而不是自由形式的 JSON。因此,我们的客户端可以享受到 IDE 中的自动补全、如果他们的语言支持类型安全带来的类型安全,以及客户端和不同版本的服务器之间强制兼容性带来的好处。

gRPC 的最后一个好处是我们能够快速规范端点。proto 格式对于数据和服务定义都极大地简化了新端点的定义,并最终实现了端点契约的简洁定义。这意味着我们能够更好地在我们开发团队之间沟通端点规范。gRPC 意味着我们公司首次能够同时开发 API 的客户端和服务器端!这意味着我们生产带有配套 SDK 的新 API 的延迟已显著降低。结合代码生成,它使我们能够真正地并行开发客户端和服务器。

我们使用 gRPC 的体验是积极的,尽管它并不能完全消除向合作伙伴和供应商提供端点的难度,也不能解决我们所有的性能问题。然而,它确实在端点性能、与这些端点的集成以及甚至在 SDK 的交付方面带来了改进。