February 05, 2025

Cloudflare、Unikernels 和裸金属:Prisma Postgres 查询的生命周期

Prisma Postgres 是市场上最具创新性的 PostgreSQL 数据库。在本文中,我们将深入探讨其技术栈,它支持闪电般的快速查询、全局缓存、连接池等功能。

回顾:什么是 Prisma Postgres?

如果您还没听说过:Prisma Postgres 是第一个基于 unikernel 构建的数据库。如果您错过了,这里有一个 100 秒的快速摘要

构建在下一代基础设施之上

Prisma Postgres 不仅仅是另一个 AWS 封装!其架构是从第一性原理精心设计的,并基于 unikernelUnikraft CloudCloudflare Workers 等下一代基础设施。

这些技术的结合提供了独特的优势和强大的功能集。

无冷启动、全局缓存、连接池等

开发者在使用 Prisma Postgres 作为他们的无服务器数据库时可以获得以下好处

  • 零冷启动:立即访问您的数据库,无需延迟。
  • 慷慨的免费层级:每月 10 万次操作、1GiB 存储空间和 10 个数据库。
  • 全局缓存层:查询响应可以在边缘轻松缓存。
  • 内置连接池:扩展您的应用程序,无需担心 TCP 连接。
  • 性能建议:AI 驱动的建议,用于加快您的查询速度。
  • 简单的按需付费定价:基于操作和存储的可预测成本。

试用 Prisma Postgres

Prisma Postgres 查询的生命周期

简短回顾之后,让我们深入了解 Prisma Postgres 用来实现这些优势的技术栈。剧透:以下是涉及 Prisma Postgres 查询生命周期的所有组件的完整概述

Prisma Postgres components

在接下来的部分,我们将仔细研究每个阶段,并解释底层发生了什么。

阶段 1:一切始于 Prisma ORM

Prisma ORM 是 Prisma Postgres 查询旅程的自然起点。

使用 Prisma Postgres 时,应用服务器上无需查询引擎

如果您以前使用过 Prisma ORM,您可能知道它使用了一个用 Rust 实现的查询引擎(Query Engine),该引擎作为二进制文件运行在您的应用服务器上。

请注意,虽然在此语境下我们仍在讨论用 Rust 编写的查询引擎,但它目前正在用 TypeScript 重写。在此了解更多

查询引擎的核心职责是

  • 根据高级 ORM 查询(用 JS/TS 编写)生成高效的 SQL 查询
  • 管理数据库连接池

然而,将 Prisma ORM 与 Prisma Postgres 结合使用的妙处在于您不需要在应用服务器上运行查询引擎。相反,您将使用一个不包含查询引擎的超轻量级 Prisma ORM 版本。生成 SQL 查询和管理 TCP 连接的繁重工作被进一步下推到堆栈中,进入位于 Prisma Postgres 之上的连接池。

在 Prisma Postgres 基础设施上托管连接池的这种方法具有主要优势:将应用开发者从连接池管理中解放出来,让他们专注于数据需求和查询。它在短生命周期环境(如无服务器和边缘函数)中也特别有用,在这些环境中反复重建连接池会导致严重的性能开销。

使用缓存策略定义 Prisma ORM 查询

为了本文的目的,我们使用以下 Prisma ORM 查询

此查询从数据库中获取所有已发布的文章,并额外指定了两个与 Prisma Postgres 缓存相关的参数

  • 存活时间(Time-To-Live)ttl):确定缓存数据被视为新鲜的持续时间。当您设置 TTL 值时,Prisma Postgres 将在该持续时间内提供缓存数据,而无需查询数据库。
  • 陈旧时重验证(Stale-While-Revalidate)swr):允许 Prisma Postgres 在后台获取新数据时提供陈旧的缓存数据。当您设置 SWR 值时,Prisma Postgres 将在该持续时间内继续提供缓存数据(即使超过了 TTL),同时使用来自数据库的新数据更新缓存。

在此示例中,数据将被视为新鲜 30 秒 (TTL)。此后,在接下来的 60 秒 (SWR) 内,Prisma Postgres 的缓存将提供陈旧数据,同时在后台获取新数据。

Prisma Postgres 从靠近您应用程序的边缘位置提供缓存数据。如果您将应用程序部署到多个位置,此全局缓存可以显著提高应用程序的性能!

通过 HTTP 执行查询

那么,当上述查询在应用程序中执行时,接下来会发生什么?由于查询引擎已被下推到堆栈中,在此阶段发生的一切是向 Prisma Postgres 基础设施的第一层认证和路由层发送 HTTP 请求。这个 HTTP 请求携带了一个轻量级的、基于 JSON 的查询表示。它看起来是这样的

请注意,selection 参数指定了应该从数据库中获取的字段。由于我们在查询中没有使用 selectinclude 选项,其值仅为 "$scalars": true,这意味着将返回目标模型的所有标量字段。

下一步是将请求由 Prisma Postgres 的认证层和缓存层进行评估。

阶段 2:认证请求

在到达缓存检查查询结果是否可以从那里提供服务之前,查询需要被认证。Prisma Postgres URL 总是包含一个 apiKey 参数,该参数编码了用户凭据

认证层使用 Cloudflare Workers 实现,因此物理位置上非常接近查询的源头。它使用 apiKey 值来识别用户,验证访问权限并将请求路由到下一阶段。

阶段 3:缓存还是不缓存

认证后,HTTP 请求将到达 Prisma Postgres 基础设施的下一层,该层也通过 Cloudflare Workers 实现

此路由层的主要目的是确定是否需要激活 Prisma Postgres 缓存

  • 如果查询设置了 swr 和/或 ttl 选项,则查询将进入 Prisma Postgres 缓存路径。
  • 如果查询没有设置这些缓存选项中的任何一个,它将直接进入下一阶段。

那么,让我们探究通过 Prisma Postgres 缓存层的路径。

Prisma Postgres 缓存构建在 Cloudflare Workers 之上,因此充分利用了官方的 Cloudflare Cache API

作为缓存键,它使用基于整个 Prisma ORM 查询(包括查询参数的值,例如上面提到的 published: true)计算得出的哈希值。这种方法倾向于缓存未命中,并且只有在 100% 确定完全相同的查询之前发送到数据库并且其结果被缓存过时,才会从缓存返回数据。

您可以在 Prisma Postgres 控制面板中查看缓存行为的统计信息

现在假设我们之前的查询继续沿着 Prisma Postgres 堆栈向下,并且未由缓存提供服务。接下来会发生什么?

阶段 4:到达连接池

如果查询结果未被缓存,之前的 HTTP 请求将被转发到下一站:Prisma Postgres 的连接池(它部署在与数据库实例物理位置非常接近的 VM 上运行)。

在我们最近的文章中了解更多关于连接池为何重要:通过连接池拯救黑色星期五

请注意,这实际上是请求可能传输更长距离的第一次(也是唯一一次),因为它现在离开了 Cloudflare 区域的边界。

这些 VM 托管着从应用服务器移出的查询引擎(如阶段 1 中所述)。因此,在此阶段,Prisma Postgres 的连接池不仅找到一个空闲连接来实际执行查询,它还生成将发送到 Prisma Postgres 的 SQL 语句。这现在通过一个经典的 TCP 连接与数据库完成。

阶段 5:进入 unikernel 数据库

Prisma Postgres 基于运行在我们自有裸金属服务器上的超轻量级微虚拟机(microVM)中的unikernels (可以理解为:“高度专业化的操作系统”)。

查看早期访问公告,了解该架构的详细信息,我们与 Unikraft 的合作,以及实现 Prisma Postgres 性能优势的毫秒级云堆栈。

以下是 Unikraft Cloud 的 核心组件概述,这些组件实现了 Prisma Postgres 实例的闪电般启动速度

这些组件协同工作的方式如下

  • 自定义控制器和代理:一个自定义平台控制器,提供一流的、响应式的毫秒级语义和可伸缩性。为了加快网络处理速度,Unikraft Cloud 将此控制器与一个自定义代理配对,该代理负责负载均衡并能够非常快速地响应传入请求。这个代理负责管理 Prisma Postgres 与连接池的 TCP 连接。
  • 基于 Firecracker 和 unikernels 的快速虚拟机监视器 (VMM):Unikraft Cloud 的 unikernels 使用仅包含 Prisma Postgres 的精简镜像——不多不少。与修改版的 Firecracker VMM 配合,这些 Prisma Postgres 镜像启动速度极快。
  • 快照:Unikraft Cloud 在将 Prisma Postgres 实例缩减到零之前,会创建其内存快照。唤醒它们时,它们从快照恢复,这意味着 VM 已经“预热”,甚至包含了已经激活的 TCP 连接!

得益于这种高效的堆栈,数据库实例仅在使用时产生费用。这使我们能够提供慷慨的免费层级,您可以根据需要启动任意数量的免费 Prisma Postgres 实例(与其他提供商不同,其他提供商通常在创建多个数据库实例时需要支付固定的月费用)。

回到我们的查询:初始的 JSON 查询表示被转换为高效的 SQL 语句后,查询最终通过 TCP 到达数据库层。PostgreSQL 实例使用 Unikraft 的毫秒级云堆栈部署在我们自己的裸金属服务器上,靠近连接池。

这里的第一站是 Unikraft 代理,它负责维护到连接池的 TCP 连接。

代理现在与 Unikraft 控制器通信,该控制器负责管理实际的 Prisma Postgres 实例。此时,有两种可能的状态

  • 要么目标 Prisma Postgres 实例已经启动并运行;在这种情况下,代理将继续直接将查询转发给它。
  • 或者 Prisma Postgres 实例当前处于“暂停”状态;在这种情况下,代理将联系 Unikraft 控制器,该控制器负责识别目标 Prisma Postgres 实例,“唤醒”它并通知代理当前的实例状态。

不要被这里的“暂停”和“唤醒”术语搞糊涂。由于超快速的 VM 快照(发生在内存中)和 unikernels 的轻量级,每个实例可以在个位数毫秒内再次被唤醒(这就是 Prisma Postgres 实例不受冷启动影响的秘密)。

Prisma Postgres 架构的下一步是什么?

虽然我们已经看到了当前技术栈及其为开发者带来的好处引发了很多兴奋,但我们不会止步于此!

我们在未来版本的 Prisma Postgres 中看到了许多可能的额外优化,最值得注意的是:我们将把连接池迁移到运行 Prisma Postgres 实例的同一机器

Future architecture diagram of Prisma Postgres

TCP 连接是整个堆栈中最昂贵的部分,因为它每次建立连接都需要进行三次握手。通过将此 TCP 连接简化为发生在同一机器上两个进程之间的本地连接,连接池和数据库实例之间的物理距离引起的延迟将变得完全可以忽略不计。

这是 Prisma Postgres 相较于基于 AWS(或其他云提供商)基础设施的其他提供商的核心优势:使用云提供商时,无法保证连接池和数据库实例在同一主机上运行,而总是会存在网络跳跃。

结论

在本文中,我们深入探讨了 Prisma Postgres 及其构建所基于的下一代技术栈。

如果您已经在用 Prisma ORM,可以通过从现有数据库导入数据来试用 Prisma Postgres。否则,请在您的终端中运行此命令从头开始试用 Prisma Postgres

不要错过下一篇文章!

订阅 Prisma 新闻简报