现代的无服务器和边缘运行时使得部署快速、可扩展的应用比以往任何时候都更容易。但随着应用越来越分布式,性能问题往往从代码本身转移到基础设施上。
本文探讨了全球分布式应用中常见的后端瓶颈:长时间的数据库往返、连接流失、冷启动和低效查询。它还将介绍连接池、缓存、区域感知部署和更智能的监控等实用解决方案——这样无论用户身在何处,你的应用都能保持快速。
边缘和无服务器的真正含义
在我们深入探讨之前,先快速定义一下这个领域。
无服务器意味着你编写一个函数,部署它,然后你的云提供商按需运行它。你无需考虑基础设施。它可以自动伸缩。
边缘意味着这些函数运行在靠近用户的地方。你的代码可能在日本为日本用户运行在东京,或在德国为德国用户运行在法兰克福。这减少了物理距离,从而降低了延迟。
这对于前端响应和轻量级 API 非常有用,但它在幕后带来了新的挑战。
无状态函数为何会使事情复杂化
其中一个挑战是无服务器和边缘函数是无状态的。它们不会在请求之间保持状态。因此,每次请求到来时,都可能会启动一个新的实例,并且没有与数据库的持久连接。
这导致了一个被称为连接流失的问题:数百个新连接被快速打开和关闭。
如果1000个用户同时访问你的函数,那在短时间内就会产生1000个数据库连接。大多数数据库并非为此而设计。你将达到连接限制,数据库会开始限流,一切都会变慢。
冷启动加剧了这个问题。如果一个函数最近没有被使用,第一次请求会比较慢,因为运行时需要启动并建立新的连接。
使用连接池
解决方案?连接池。
连接池允许多个函数调用共享一组少量且持久的连接。它就像数据库前面的队列。每个函数不再打开新的连接,而是从连接池中获取一个。
如果你使用像 Prisma Postgres 这样的数据库,连接池会在幕后处理——自动在函数之间进行连接池化和优化查询。其他工具,如 PgBouncer 或 Supavisor(来自 Supabase),也很有用。
仅为数据库使用连接池就可以在高流量的边缘环境中稳定性能。
至此,我们已经解决了如何管理过多连接的问题。但在边缘性能缓慢的背后,还有另一个隐藏的罪魁祸首。
你的边缘应用不慢,慢的是到数据库的往返时间
想象一下,你将边缘函数部署到东京。它运行得飞快——直到它调用弗吉尼亚的数据库。突然间,你的响应时间增加了500毫秒。
这不是你的代码的问题。这是地理位置的问题。
边缘运行时速度很快,但如果你的函数必须跨洋查询数据库,每个请求都会增加数百毫秒的往返延迟。将此延迟叠加到多个查询上,用户体验就会受到影响。
让我们探讨如何解决这个问题。
缓存无需实时的数据
减少不必要的数据库调用的最简单方法之一是缓存不经常变化的数据。
比如:产品列表、站点设置或功能标志。这些值无需每次都重新获取。
你可以使用以下方法缓存数据库查询:
- 使用适当的
Cache-Control
头部进行 CDN 级别缓存 - 边缘键值数据库(例如 Vercel KV,Cloudflare Workers KV)
- 在已预热的无服务器函数中进行内存缓存
- 使用具有内置缓存的数据库提供商,例如 Prisma Postgres
缓存可以减轻数据库的负载,并显著缩短重复请求的往返时间。
将函数和数据库部署在同一区域
另一种提高 API 速度的方法是将代码和数据库运行在同一区域。
假设你的数据库托管在 us-east-1
(弗吉尼亚)。但你的边缘函数是从东京调用的。如果函数运行在靠近用户的地方(例如 ap-northeast-1
),而数据库却远在大洋彼岸的美国,那么每次查询都必须进行一次长距离网络往返——而且是多次。
这就是延迟迅速累加的地方。
函数可能看起来像这样:
如果函数靠近用户(在东京),但远离数据库(在弗吉尼亚),每次数据库查询都会花费时间——由于跨太平洋网络延迟、TLS 握手和 DNS 解析,每次往返大约需要300毫秒。
这个处理器会依次运行三个相互依赖的查询
- 3个查询 × 300毫秒 = 总延迟约 900毫秒
因此,即使你的函数还没有开始做任何实际工作,仅仅是等待数据就花费了近一秒钟。
现在将它们部署在同一区域
通过将函数与数据库部署在同一区域(弗吉尼亚),这些查询不再需要跨越海洋。它们保持本地化——通常每个查询在10–30毫秒内完成。
这意味着整个响应可以在不到90毫秒内返回,即使请求来自东京。用户仍然会经历一些与距离相关的延迟,但你的后端会保持快速和一致。
区域固定使其生效
Vercel、AWS Lambda 等平台允许你将函数固定到特定区域——在本例中是 us-east-1
。
对于 Vercel 中的边缘部署,region
配置可以让你固定区域
这种设置在以下情况下是理想的:
- 你顺序运行多个查询
- 你想避免编写复杂的客户端缓存
- 你关心稳定、低延迟的 API
将计算资源与数据 colocating,而不是将后端分散到全球各地,只需一行配置即可避免数百毫秒的开销。
何时考虑多区域数据库
如果你的大多数用户都在读取数据并且分布在全球各地,多区域数据库会有所帮助。
这会将你的数据复制到多个区域,因此欧洲、亚洲或澳大利亚的用户会从他们最近的副本读取数据。这可以改善延迟并减轻单个数据库节点的负载。
AWS 等云提供商提供了多区域功能,例如 DynamoDB 全局表和 Aurora Global,但像 CockroachDB 这样的专用数据库也使得跨区域复制数据变得容易,从而获得更好的性能。
分布式数据库在以下情况下是很好的选择:
- 读取量远大于写入量
- 轻微的数据过时(最终一致性)可以接受
- 你想减少全局往返
但如果出现以下情况,请暂时不要使用:
- 你的应用需要严格的一致性(例如金融交易)
- 你在许多区域有频繁的写入操作
- 你需要精确控制版本冲突
关注你的查询
即使你使用了缓存和 colocated 部署,糟糕的查询仍然会成为性能瓶颈。
尽早设置监控以跟踪百分位延迟
- p50 = 中位数查询时间
- p75 = 较慢的查询,通常在轻负载下出现
- p99 = 最差情况下的查询,通常是性能问题隐藏的地方
例如,p50 为 30 毫秒很棒——但如果你的 p99 为 700 毫秒,那么一些用户仍然会经历痛苦的延迟。
在识别性能瓶颈时,还要注意:
- N+1 查询模式
- 过滤字段上缺失索引
- 过度获取嵌套数据
仅改进几个繁重的查询就可以将你的整体延迟减半。Prisma Optimize 等工具通过识别边缘和无服务器函数中最慢的查询、查明根本原因并提供可行的修复建议,从而简化了这一过程。
快速回顾
这里快速回顾一下问题和解决方案。
问题 | 解决方法 |
---|---|
长时间数据库往返 | 将计算资源与数据库部署在同一区域 |
连接过多 | 添加连接池 |
重复读取 | 在边缘缓存 |
全球延迟 | 考虑多区域数据库 |
查询缓慢 | 使用 Prisma Optimize 或 Datadog 等监控工具 |
总结
部署到边缘很容易。但要让你的应用感觉快速——尤其是在全球范围内——则需要多花些心思。
好消息是?你不需要重建整个技术栈。一些小的改变——缓存、colocating、连接池和监控——就能带来巨大的差异。
下次你的边缘函数开始感觉慢时,很少是计算本身的问题。十有八九是你的数据库的问题。通常延迟就始于数据库,提速的空间也在这里。
让我们继续交流
如果本文对你有所帮助,我们很乐意听到你的反馈。在 X 上标记我们,分享你正在构建的内容。或者加入我们的 Discord,如果你想聊天、解决问题,或者深入探讨数据库和性能。
我们还定期在 YouTube 上发布深度视频。如果你对这些内容感兴趣,请订阅。更多示例、更多性能技巧,也许还有一些意外发布。我们 YouTube 见。
不要错过下一篇文章!
订阅 Prisma 新闻通讯