RSS

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

Vendasta 始于 8 年前,最初是一家为小型企业提供产品的单点解决方案提供商。从一开始,我们就与那些拥有大量销售团队并与这些企业建立现有关系的媒体公司和代理机构合作,由他们来销售我们的软件。据估计,仅在美国就有超过 3000 万家小型企业,因此我们的 SaaS 解决方案的可扩展性从一开始就被视为我们最关心的问题之一,这也是我们选择 Google App Engine 和 Datastore 的原因。当我们的系统从数百名终端用户扩展到数十万名时,该方案运行得非常出色。在此期间,我们也成功地将我们的产品从单点解决方案扩展为一个完整的平台,不仅包含多种产品,还为合作伙伴提供了管理这些产品销售的工具。

在整个过程中,Python GAE 很好地满足了我们的需求。我们通过 HTTP + JSON 公开了一些 API,方便合作伙伴自动执行任务,并将他们的其他系统与我们的产品和平台集成。然而,在 2016 年,我们推出了 Vendasta Marketplace。这标志着我们产品方案的重大转变,该转变极度依赖于第三方供应商使用我们的 API 来在我们的平台上交付他们自己的产品。这是一个重大的变化,因为我们的公共 API 为第三方应用程序提供了上限,这也让我们意识到,我们确实需要制作出卓越的 API,而不仅仅是“好用”的 API。

我们开始的第一项优化是使用 Go 编程语言来构建端点,以处理比使用 Python 更高的吞吐量和更低的延迟。在某些 API 上,这种差异令人难以置信:我们看到 50 分位响应时间从 1200 毫秒下降到 4 毫秒,更令人惊叹的是 99 分位响应时间从 30,000 毫秒下降到 12 毫秒!在其他 API 上,虽然差异较小,但仍然非常显著。

我们使用的第二项优化是将大量 Datastore 数据复制到 ElasticSearch。ElasticSearch 是一种与 Datastore 截然不同的存储技术,而且它不是一项托管服务,所以这对我们来说是一个巨大的跨越。但这一改变使我们能够将几乎所有隔夜批处理 API 迁移为实时 API。我们尝试过 BigQuery,但其查询处理时间意味着我们无法实时显示内容。我们尝试过 CloudSQL,但数据量太大,难以轻松扩展。我们还尝试过 App Engine Search API,但它在处理超过 10,000 条的结果集时存在局限性。取而代之的是,我们使用 Google Container Engine 扩展了我们的 ElasticSearch 集群,凭借其强大的聚合和分面处理功能,我们的需求得到了轻松满足。因此,通过这两项初步解决方案,我们已经实现了对 API 性能的重大改进。

我们进行的最后一项优化是将 API 迁移到 gRPC。这一变化比之前的优化更为深远,因为它影响到了我们的客户端。与 ElasticSearch 一样,它代表了一种具有不同性能特征的根本性不同模型;但与 ElasticSearch 不同的是,我们发现它是一个真正的超集:我们所有的使用场景都从它那里获得了积极的影响。

我们从 gRPC 中获得的首个好处是,能够从“发布 API 并要求开发人员与之集成”转变为“发布 SDK 并要求开发人员复制粘贴用他们熟悉的语言编写的示例代码”。对于那些希望与我们产品集成的开发人员来说,这代表了巨大的福利,同时我们也不需要为我们的合作伙伴和供应商使用的 5 种以上的语言手动编写整个 SDK。值得注意的是,我们仍然会在生成的 gRPC SDK 之上编写轻量级包装器,以使其更符合包管理器的习惯,并为生成的 protobuf 结构提供封装。

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

第三个好处是从 JSON 切换到 Protocol Buffers,这与 gRPC 配合得非常好。它缩短了序列化和反序列化的时间;这对我们的一些 API 来说非常重要,而且对所有 API 都有所提升。更重要的好处来自 Proto 的明确格式规范,这意味着客户端接收到的是类型化对象,而不是格式自由的 JSON。因此,我们的客户端可以享受 IDE 自动补全带来的便利、语言支持下的类型安全,以及在不同版本客户端和服务器之间强制执行的兼容性。

gRPC 的最后一个好处是我们能够快速规范端点。用于数据和服务器定义的 Proto 格式极大地简化了新端点的定义,并最终允许简洁地定义端点契约。这意味着我们能够更好地在开发团队之间沟通端点规范。gRPC 意味着在我们的公司历史上,我们第一次能够同时开发 API 的客户端和服务器端!这意味着我们生产新 API 及其附带 SDK 的延迟大幅下降。结合代码生成,它使我们能够真正地并行开发客户端和服务器。

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