返回资讯中心
外部精选
软件工程
#开发者实时流

应用该用本地数据还是更快的Postgres?先诊断慢的根源

来源标题:Does your application need local data or faster Postgres?

在给应用加本地数据副本之前,应先弄清它为什么慢。本地同步会引入额外复杂度,尤其AI代理不断改变工作集、难以预测。文章对比本地数据同步与快速中央NVMe Postgres架构,探讨后者能否从一开始简化系统。

Hacker News 最新lio_db2026/11/3 · 今天29 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

在为了提速而给应用加本地副本之前,先问清楚它一开始为什么慢。本地同步会带来复杂性,尤其是当 agent 不断改变工作集时。一个由 NVMe 支撑的快速中心化 Postgres 提供了更简单的起点:直接查询,并通过副本扩展读能力。

应用需要快速的读写,否则就不可用。当主 Postgres 实例无法提供良好性能时,一种现有解决方案是把部分工作集同步到离应用更近的地方。读变成本地读,对中心数据库的压力也减小了。这可能有好处,但代价是多了一层需要管理的数据,而写仍然依赖中心 Postgres。

本文中,我们将探讨本地数据同步如何工作、为什么 AI agent 让本地工作集更难预测,以及一个更快的中心 Postgres 实例是否可能从一开始就简化架构。

许多托管 Postgres 服务把数据保存在网络附加存储上。例如 Amazon RDS for PostgreSQL 把数据存储在通过网络访问的 EBS 卷上,每个卷都有自己的 IOPS 和吞吐量上限。其他服务(如 Neon)走得更远,把计算与存储完全分离。这些设计让你获得在计算节点丢失后仍能存活的存储,以及灵活的资源配置,但每一次缓存未命中的读都必须跨网络。

一旦工作负载变成 I/O 密集型,这就成了问题。此时增加计算并不能让数据库变快。读仍然要从存储取页,写仍然要生成 WAL,而 VACUUM 之类的后台任务还要争抢同一份 I/O 预算。随着并发上升,查询变慢,尾延迟增大。

这就是为什么托管 Postgres 上的应用常常随着使用量增长而变慢,即使 CPU 和内存看起来都正常。在添加本地数据层来绕过这一延迟之前,先检查真正的瓶颈是不是数据库底层的存储。

开发者需要预先声明子集:哪些表、哪些行(通常是对租户列或用户列的过滤条件)、哪些列。在多租户应用中,一个客户端的子集通常就是该租户的行,别无其他。每个声明相同子集的客户端都会收到相同的变更流,因此当许多客户端需要相同数据时,同步层的成本是分摊的。

子集就位之后,子集内任何内容的读都是本地读。界面、表单和仪表盘查询本地存储,对这些读来说,到 Postgres 的往返从读路径上消失了。子集之外的读仍然要访问数据库,或者必须先扩大子集。

应用换来的是其部分数据的第二份副本,并且这份副本有自己的生命周期。必须有人决定什么属于子集、子集何时变化、客户端保留它多久,以及 schema 变化时会发生什么。对于离线运行或在不可靠网络上运行的应用,以及许多客户端读取相同且稳定的工作集的应用,这是值得的。当唯一需求是从一个连接良好的在线数据库获得快速读时,它的价值就不那么明显了。可预测的查询让子集容易声明。但仅凭这一点,并不意味着你需要一份本地副本。

同步层只处理读路径,因此应用必须为中央 Postgres 维护一条单独的写路径,通常通过自己的 API。事务提交后,变更通过逻辑复制流出,经过同步层,进入每一个声明子集包含受影响行的本地存储。因此一次写会在客户端产生两个独立事件:API 响应,以及已提交变更随后不久到达本地数据集。

为了掩盖这一间隙,应用会保留乐观状态。变更在服务器确认之前就被立即应用到本地视图。然后应用必须把这一临时状态与通过同步流到达的内容进行对账,后者既包括自己这次写的已提交版本,也包括其他客户端对相同行的写。当自己的写出现在流中时,临时副本被丢弃。如果写被拒绝,临时副本必须回滚,视图也要修正。

Postgres 自始至终是权威来源,它仍然是并发写通过事务排序的地方。直接从 Postgres 读取已提交状态的应用免费获得这种排序。它从不需要等待本地副本追赶,也从不需要持有同一行的两个版本。本地副本以快速读为交换,换来一个应用必须自己承担的对账问题。待处理的本地变更、异步到达的已提交数据,以及用户看到的视图,三者必须保持一致。

传统应用面对的是有界的工作集,因为人们以可预测的模式在其中导航。产品页加载产品信息,账单页加载某个特定账户,搜索页查询一组给定字段。AI agent 的行为不同:它可以加载一个产品,找出买过它的客户,然后寻找相似产品,所有这些都基于运行时提供的 prompt 和上下文。

如今范式已经不同。有了 agent,开发者无法总是预测应用的工作集,也无法准确界定其边界。声明子集仍然可行,但工作集边界必须足够宽,以支撑 agent 可能的查询路径。按需加载和渐进加载可以避免预先同步整个子集,但尚未物化的数据在可本地查询之前仍然需要一次远程请求。

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →