您的 RAG 流水线的 延迟讨论可能卡在了错误的问题上。团队对 GPU 进行基准测试,调整 HNSW 参数,争论 ef_search 的数值,并将近似 最近邻搜索 的延迟降低个位数毫秒。与此同时,存储其嵌入向量的向量数据库与运行其模型的 GPU 位于不同地区,每次检索调用都需要支付由两座建筑之间距离决定的往返税。没有任何索引参数能够弥补这段时间。光速没有配置开关。
本文围绕该差距做了三件事:通过计算器可验证的物理推导出税的下限,展示了税在多跳代理 RAG 中如何累积:一次原本不可见的每次调用成本会变成每项任务的纯地理秒数,并提供一个测量工具,以在 DigitalOcean GPU Droplets 和 向量数据库 上测量您自己的路径,使得争论以您的数字而非我的数字结束。
本文数据的来源。 两个来源,严格分开。往返下限(5.5 ms、41.3 ms、62.0 ms、153.3 ms 及其余值)是通过将大圆距离除以光在光纤中的传播速度(约 200,000 km/秒)得出的。它们是物理设定的下限,而非测量值;实际路径更慢,因为光纤并不沿大圆行进。测量列来源于我于 2026 年 8 月 10 日在实时 DigitalOcean GPU Droplets 和 向量数据库(PostgreSQL 带 pgvector)上运行的公开测试工具。测试脚本和结果位于我创建的 GitHub 仓库中:anishsingh20/data-locality-tax。
| 术语 | 通俗解释 | 示例 |
|---|---|---|
| RAG (retrieval-augmented generation) | 应用先查找相关事实,然后让语言模型基于这些事实来回答,这样模型就不是仅凭记忆猜测。 | 客服机器人会在你的文档中搜索 “退款政策”,然后根据找到的片段撰写回复。 |
| Vector / embedding | 一串代表文本(或其他项目)意义的数字列表,使相似的概念在数学空间中彼此靠近。 | 句子 “我该如何重置密码?” 会转换为 768 个数字;相似的帮助文章的数字则位于附近。 |
| Vector database | 一种专门用于存储这些数字列表并快速查找最近匹配的数据库。 | 带有 pgvector 的 DigitalOcean 托管 PostgreSQL、OpenSearch 或 Weaviate,用于保存你的知识库块。 |
| Data locality tax | 由于数据库和 GPU 相距较远,每次查询都会产生额外的等待时间:这是你无法通过调整来消除的距离开销。 | GPU 位于纽约,向量数据库位于旧金山:在测试运行中每次汇总搜索约需 67 毫秒;当两者都在 NYC3 时,延迟降至 2 毫秒以下。 |
| Latency | 某个操作从开始到结束所需的时间,通常以毫秒(ms)为单位。1000 毫秒等于 1 秒。 | 同一数据中心内的搜索耗时 2 毫秒,而跨区域搜索则需 67 毫秒。 |
| Round trip (RTT) | 请求发送到另一台机器并收到回复所需的时间。 | 仅打开连接然后关闭的 TCP 探测(不涉及数据库操作)在纽约到旧金山的路径上仍需约 69 毫秒。 |
| Latency floor / physics floor | 在光纤中受光速限制、以及城市间距离决定的理论最低延迟。实际网络会更慢。 | 无论软件多么优秀,纽约到旧金山在光纤中的往返延迟也无法低于约 41.3 毫秒。 |
| Speed of light in vacuum | 光在真空中的传播速度:约每秒 300,000 公里。这是绝对的宇宙速度上限,而光纤永远无法达到此速度。 | 仅作参考使用。 |
CREATE INDEX ...USING hnsw on the items table in the runbook.ef_searchef_search。在测量任何数据之前,我们先来拆解一次向量搜索调用的组成部分,因为拆解本身就是论证的核心。这是我在本文中试图强调的关键区别:索引调优优化的是组件部署位置无法触及的部分,而部署位置决定了调优无法触及的组件。一个团队在数据库位于大洲另一端时还在benchmarking ef_search取值,这相当于在打磨一条慢路径上的快部分。
从你的应用程序决定发起搜索到结果可用,一次检索调用在五个环节上耗费时间。
按控制因素对这五部分进行归类。ANN搜索时间取决于索引参数、硬件和语料库规模。而其他所有部分都取决于部署位置和连接管理纪律。
五个阶段,两个所有者。调优拥有青绿色阶段。地理位置负责红色阶段,且没有任何索引参数能够影响它们。来源:作者对一次检索调用的分解;检索块预填行为遵循 DigitalOcean 的端到端 RAG 教程 中的管道阶段以及 p50 与 p99 延迟 中的 TTFT 框架。
这直接影响用户体验,而不是隐藏在仪表盘中,原因在于检索块预填。
在标准的 RAG 流程中,模型只有在拿到检索到的上下文后才能开始处理提示词,因此检索路径上的每一毫秒都会增加首次 token 生成时间,这是用户在看到任何内容之前一直关注的指标。
光在光纤中的传播速度大约为每秒 200,000 公里,约为真空中光速的三分之二,这是因为光纤的折射率。这个数值把距离转化为无法通过工程手段消除的延迟下限。将两城市之间的大圆距离除以每秒 200,000 公里,再乘以 2 得到往返时间,这就是它们之间的最小可能往返时间,在出现排队、路由绕道或服务器进行任何工作之前。
本文数据的来源。 下表是我根据该方法自行推导的。我使用哈弗赛尔公式和每个都市区的坐标计算了每个大圆距离。这些是下限,而非实际性能的估计:生产光纤路线不遵循大圆路径,因此实际往返时延会超过这里的每个数字。
| 路径 | 大圆距离 | 光纤往返下限 |
|---|---|---|
| 单个数据中心内部 | 低于 1 km | 低于 0.01 ms |
| 纽约至多伦多 | 550 km | 5.5 ms |
| 纽约至旧金山 | 4,129 km | 41.3 ms |
| 纽约至伦敦 | 5,570 km | 55.7 ms |
| 纽约至阿姆斯特丹 | 5,863 km | 58.6 ms |
| 纽约至法兰克福 | 6,203 km | 62.0 ms |
| 纽约至班加罗尔 | 13,368 km | 133.7 ms |
| 纽约至新加坡 | 15,332 km | 153.3 ms |
| 纽约至悉尼 | 15,989 km | 159.9 ms |
将第一行与其余行对比,因为第一行是整个架构论点。同一 DigitalOcean 数据中心内的 GPU Droplet 和托管向量数据库通过 VPC 网络通信,其传播下限比任何跨区域配对低三个数量级。DigitalOcean 自己的 VPC 文档 确认了相关属性:VPC 网络仅限于单个数据中心区域,VPC 内部流量免费且私密,跨数据中心连接 VPC 需要 VPC 对等互连,该服务在所有数据中心之间均可用,除了 BLR1 外,按跨数据中心流量收费 $0.01 每 GiB。物理和定价指向同一方向。
这是推导得出的,而非实际测量。实际路径的时延会慢于图中每个柱子所示的数值,因为光纤并不沿着大圆路径敷设。第一个柱子是论点的基础。来源:作者的推导,哈弗赛因大圆距离除以约 200,000 公里/秒的光纤传播速度,再乘以 2 得到往返时延;方法及完整表格见本文的“基准”部分。
这是 harness 存在的章节。下面的设计已经完全指定;harness 和原始结果已在我创建的 GitHub 仓库中发布:数据局部税 — — 跨地区检索延迟测量。
我在 2026 年 8 月 10 日进行了此测试。我从 NYC3 Droplet 向 NYC3 和 SFO3 的托管 PostgreSQL 16 + pgvector 填充了 Arms A、B1 和 B2(每个单元格使用 10 万个合成的 768 维向量,HNSW 余弦,在 10 次预热后进行 75 次试验)。
在固定区域的一个 GPU 实例(推荐使用 NYC 区域),运行嵌入模型和 LLM。一个语料库,大约包含 100 万个向量,维度为现实中的 768 或 1,024,在所有被测存储中以完全相同的方式加载。在引擎允许的情况下,各臂的索引类型和参数保持一致,这样服务器端的 ANN 时间在比较中相互抵消,剩余的差异仅反映路径的影响。
Arm A,同一数据中心通过 VPC A DigitalOcean 向量数据库 与 GPU Droplet 位于同一数据中心,附加到同一 VPC,通过专用网络进行查询。由于托管 PostgreSQL 在各地区广泛可用,带有 pgvector 的 PostgreSQL 是最安全的引擎选择。OpenSearch 是混合搜索工作负载的替代方案,Managed Weaviate 根据 Vector Databases 发行说明于 2026 年 7 月 1 日进入公开预览,因此在将其作为一个 arm 配置之前,请查看您所在地区配对的可用性页面。
您可以参考 在 OpenSearch、Weaviate 和 pgvector 之间进行选择 以获取更多关于选择权衡的信息。
Arm B,远程 DigitalOcean 区域 相同的数据库,相同的引擎,相同的计划,相同的索引,在远程区域进行配置:大陆情况下的 NYC 到 SFO。通过公共端点进行查询,并在配置了的情况下,此外还通过数据中心间 VPC 对等互连进行查询,两条路径分别记录。
Arm C,第三方托管向量存储 一种 SaaS 向量数据库,尽可能按照其套餐层级匹配地区。现在提出一个框架规则,以便结果部分继承它:此 arm 的目的不是为了点名道姓地指责供应商对其无法控制的物理现象。它之所以存在,是因为许多团队默认使用 SaaS 向量存储,却从未检查其集群实际所在的地区,而 arm C 用来衡量这种未经审查的默认选择所带来的成本。在结果中披露地区匹配的尝试以及供应商声明的地区。目标是决策模式,而非供应商。
每个 arm,每种配置:在剔除预热后,每个单元至少 75 个请求,跨两个时间窗口,报告 p50、p95 和 p99,遵循来自 无服务器推理中重要的指标 的测量标准。
每个单元格在 top-k 取值为 5、20、100 下运行,以暴露载荷大小与距离的交互作用;每个单元格分别记录冷连接和池化连接的时序,因为池化混淆变量值得拥有独立列,而不是污染平均值。测试套件还会对每个臂执行裸 TCP 连接探测,这近似于一次无数据库工作的网络往返,从而得到测量的路径底线,可与推导出的物理底线并列。
相同的语料库、相同的索引、相同的查询。唯一的变量是路径,这就是重点。来源:本文的实验设计;臂的定义参见 DigitalOcean 向量数据库 和 VPC 文档;试验次数参见 服务器无推理中的重要指标。
客户端使用的是位于 NYC3 的 Droplet(s-2vcpu-4gb, Ubuntu 24.04),存储为托管的 PostgreSQL 16 + pgvector,方案为 db-s-1vcpu-1gb,数据集为相同的 100k × 768 维 HNSW。测试时间窗口为 10:04–10:05 UTC。完整 JSON 见:anishsingh20/data-locality-tax。
| 方案 | 路径 | TCP RTT 探测 p50 | 检索 p50 (k=5) | 检索 p95 (k=5) | 检索 p50 (k=100) | 冷连接首次调用 |
|---|---|---|---|---|---|---|
| A | 同一数据中心,VPC(NYC3 私有) | 2.43 ms | 1.90 ms | 3.51 ms | 11.37 ms | 111.34 ms |
| B1 | NYC3 到 SFO3,公共网络 | 68.63 ms | 66.97 ms | 69.55 ms | 70.11 ms | 717.91 ms |
| B2 | NYC3 到 SFO3,对等 VPC | 67.73 ms | 69.90 ms | 70.57 ms | 75.44 ms | 668.87 ms |
以下是此表格的含义:
为了让事情更易理解,我制作了这些图表来说明得更清楚:
下面的图表是根据 anishsingh20/data-locality-tax 中的原始 JSON 渲染得到的。重新运行 python3 analysis/plot_results.py,图形将随文件一起移动。

*_tcp.json 和 *_k5.json 文件。*
*_k5.json、*_k20.json、*_k100.json

a_k5.json 和 b1_k5.json,乘以跳数。
*_k5.json
单次 RAG 对每个用户查询执行一次检索。代理 RAG 会执行多次检索,且是顺序的,因为每跳的结果决定下一跳的查询:检索、推理、再次检索、重新排序、获取邻居、验证。每任务五到十次顺序检索是代理模式的常见形式。顺序意味着税费相加。
| 每次调用税 | 1跳 | 5跳 | 8跳 | 10跳 |
|---|---|---|---|---|
| ~1 ms (同一数据中心,预期顺序) | 1 ms | 5 ms | 8 ms | 10 ms |
| 41.3 ms (NYC-SFO floor) | 41 ms | 207 ms | 330 ms | 413 ms |
| 62.0 ms (NYC-FRA floor) | 62 ms | 310 ms | 496 ms | 620 ms |
| 153.3 ms (NYC-SGP floor) | 153 ms | 767 ms | 1,226 ms | 1,533 ms |
这些是楼层乘以跳数得到的,是对推导数字的纯粹算术,实际总数位于每个单元格之上。
中间的行讲述了故事:大陆错位导致每个 8 跳代理任务额外花费三分之一到半秒的纯地理延迟,而跨洲错位则超过一秒,在任何查询执行之前,任何 token 生成之前,对每个任务而言,这种开销将永远存在,直到有人移动数据。
相同的每次调用税乘以代理实际检索的次数。平坦的线代表 colocations 带来的收益。来源:作者的算术,本文推导出的光纤楼层乘以跳数;实际总数位于每条线之上。
对于一次检索的聊天查询,生成耗时 2 秒,跨地区税费 62 毫秒仅占响应时间的 3.1%——这是真实存在的、可测量的且能够承受的开销;如果这正是你的工作负载特征,那么进行索引调优和缓存比迁移更值得你投入一周的精力。对于每个步骤仅生成很短时间的 8 跳代理任务,累计的 496 毫秒税费已不再是可以忽略的误差:相对于每步平均生成 300 毫秒的步骤,地理位置使任务的关键路径增加约 17%;相对于更短的工具选择步骤,这一税费几乎与计算本身持平。这两个说法都是基于同一推导税费的算术计算。最终的判断取决于工作负载本身,而非税费。
冷连接需要支付 TCP 握手、一次往返,然后是 TLS 握手,在 TLS 1.3 上再加一次往返,在 TLS 1.2 上再加两次往返,之后才能发送查询。这是协议的算术运算,而非实际测量。在同一数据中心的路径上,这些握手只需几毫秒,基本无人察觉。
在 62 毫秒的跨地区路径上,相同的握手每连接会产生 124 至 186 毫秒的纯粹设置开销。如果客户端错误地配置为每个请求都打开一个新连接——这正是无服务器函数和快速编写脚本的常见默认行为——则每次调用都会承担设置税,大约使地理位置费用增加三倍。连接池 是免费的,能够消除整个倍增因子,因而成为最廉价的解决方案;它不会减小税额,而是阻止你三次支付该税。
相同路径,相同查询,费用翻三倍。连接池是本文中最便宜的开支项。来源:根据 TLS 1.3 规范(RFC 8446)和 TLS 1.2(RFC 5246)的握手往返次数,应用于本文推导的 62 毫秒纽约-法兰克福基准。
每个档次的税费是物理设定的推导基准,以及仅靠测量得到的模板条目。
档位 1,同一数据中心通过私有网络。 GPU Droplet 和向量数据库位于同一个 DC、同一个 VPC。传播延迟低于 0.01 毫秒,实际往返时间预计在个位数毫秒范围内,VPC 内部流量免费,依据 DigitalOcean 的 VPC 文档。这是测试 harness 建立的测量基准,其他档位的费用均相对此基准定价。
档位 2,同一地区,不同放置。 同一都市区,使用公共端点而非 VPC,或资源位于同一地区的兄弟数据中心。基准低于 1 毫秒,实际成本主要由路由而非距离决定。通常可以接受,通常也不必要,因为档位 1 可用。
档位 3,跨地区,同一提供商。 纽约到旧金山和纽约到新加坡的链路:基准分别为 41.3 毫秒和 153.3 毫秒,另外如果保持路径私有,则跨数据中心 VPC 对等互连费用为每 GiB 0.01 美元。此时的税费高于大多数调校良好的 ANN 搜索,意味着网络主导了检索调用。
档位 4,跨提供商,第三方 SaaS 存储。 包含档位 3 的一切,此外还有您可能从未刻意选择的地区、提供商之间的互联网路径,以及您无法观察到的供应商自身负载。臂 C 测量此档位的实际成本。反复出现的失败模式不是选择此档位,而是默认落在此档位上且从未检查。
第5层,未完整测量即被标记:基于对象存储的检索。 从对象存储提供的索引,即真正的冷存储层。如果可行,则在测试套件中进行一次指示性测量,仅作指示披露。底层逻辑仍然适用,存储延迟叠加在其上。
架构含义颠倒了通常的优化顺序:先将数据与计算共置,再调优索引。 索引调优可以恢复毫秒级延迟,而这一段的放置从未涉及。放置每次调用可以恢复十到几百毫秒,而这些段的调优从未触及。先做大而乏味的结构性修复,再做小而有趣的参数化调整。
五个层级的定价:在物理能够给出答案的地方由物理决定,在仅能通过测试套件得到的地方由测试套件决定。不要超过你的工作负载所能承受的高度。来源:本文推导得出的楼层;VPC 范围划分、免费的 intra-VPC 流量,以及每 GiB $0.01 的跨数据中心对等互连,依据 DigitalOcean VPC 特性 和 VPC 可用性,已于 2026 年 8 月 6 日验证。
局部性在以下情况下至关重要: 您的工作负载是代理式或多-hop RAG 时,因为顺序跳会将开销乘倍。当您对 TTFT 有严格预算时,因为检索会阻塞预填充,且开销完全落在用户首先感知的数量上。当查询量很大时,因为开销与量的乘积也是一种出流量和对等互连成本的故事,每 GiB 跨数据中心收费 $0.01。以及当您的架构在顺序阶段重新排序或获取邻居时,这其实是多-hop RAG 只是换了个名字。
局部性在何时可以协商 您的流程在长生成之前执行一次检索,比例检查显示开销为 3%。当您的管道是异步或批处理时,没有人会等待任何单个调用。此外,当语料库因合规或驻留原因必须位于特定地区时,决策将由系统为您完成,剩余的操作是将计算向数据迁移或将索引复制到计算区域,取决于您的更新率哪种更便宜:变化缓慢的语料库复制效果良好,变化快速的语料库通常会将计算拉向自身。
首先,找出您的向量存储实际上运行在哪里,因为许多团队无法回答这一点:对于 DigitalOcean 托管引擎,区域在集群创建时明确给出;而对于 SaaS 商店,区域隐藏在集群设置页面,大多数人在注册时最后看到。
其次,如果您使用托管 RAG 路径,请在 GPU Droplet、向量数据库和知识库之间有意匹配区域:知识库和 MCP 教程 已经包含区域放置指导。
第三,在预配置实验臂之前,请在您选择的配对上的确认引擎可用性,访问可用性页面,因为 Weaviate 处于公开预览阶段,其区域列表可能落后于 PostgreSQL 和 OpenSearch。引擎选择本身在现有的如何为您的 RAG 架构选择合适的向量数据库教程中有所涵盖。
DigitalOcean 产品需求。如果您想从实际提供模型服务的机器上进行测量,可以在您的固定区域使用一个 GPU Droplet;而在同一数据中心内的普通 CPU Droplet 对网络测量本身的效果完全一致,因为测试工具测量的是路径,而非 GPU。使用 PostgreSQL 引擎的两个 Vector Database 集群:一个与 Droplet 位于同一数据中心(用于 A 组),另一个位于远端区域(用于 B 组),两者均采用最小套餐,因为语料库是合成的且索引很小。每个区域的默认 VPC(所有资源自动加入),以及如果您需要 B2 私有路径单元,还可以在两个区域之间建立可选的 VPC 对等连接。C 组需要一个第三方 SaaS 向量存储账户,并将其区域设置截图以用于披露。
Droplet 上的工具。Python 3(DigitalOcean 镜像预装)、通过 pip install "psycopg[binary]" 安装的测试工具唯一依赖项,以及通过 apt install postgresql-client 安装的 PostgreSQL 客户端,用于加载语料库。doctl 是可选的,用于从命令行创建集群,而不是通过控制面板。
步骤 1:创建两个集群。在 Vector Databases 页面中,在 Droplet 的数据中心创建一个 PostgreSQL 集群(用于 A 组),并在远端区域创建另一个(用于 B 组),两者采用相同的套餐。将两个区域记录到结果文件中。
步骤 2:锁定访问权限并收集连接字符串。将 Droplet 添加到每个集群的受信任来源中。每个托管集群都会公开两个主机名:私有主机名通过 VPC 访问集群,仅在同一数据中心网络内部有效;公有主机名则通过互联网路由。A 组使用私有主机名。B1 组使用公有主机名;如果您配置了对等连接,B2 组则通过对等的 VPC 使用私有主机名。将每个连接字符串导出为独立的 DSN 环境变量,以免各次运行在不知不觉中混淆不同组。
步骤 3:将相同的语料库加载到两个集群中。相同的表、相同的维度、相同的索引、相同的参数。使用 psql "$DSN_ARM_A" 加载,然后针对 B 组再执行一次:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(768));
INSERT INTO items (embedding)
SELECT ARRAY(SELECT random()*2-1 FROM generate_series(1,768))::vector
FROM generate_series(1,100000);
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
100,000 个合成向量可以保持加载快速且比较公平,因为相同的语料库和相同的索引参数会抵消臂对臂增量中的 ANN 时间。如果你想要生产级别的索引深度,可将其扩展到 100 万,并记录你使用的数量。这里使用随机向量也没关系,因为此实验测量的是路径,而不是召回率。
步骤 4. 首先对每个臂运行 TCP 探测。 DigitalOcean 托管的 PostgreSQL 监听在端口 25060。该探测不需要数据库凭据,近似等于一次原始网络往返:
python3 locality_bench.py --mode tcp --host <arm-a-private-host> --port 25060 --out a_tcp.json
python3 locality_bench.py --mode tcp --host <arm-b-public-host> --port 25060 --out b1_tcp.json
注意:文件/Python 脚本
locality_bench.py位于下一节,并且我也在创建的 GitHub 仓库中提供了该文件 局部性基准脚本.py,用于此测试。
将每个探针的 p50 放在该路径推导出的基准旁边。差距即为路径相对于物理极限的开销;如果探针落在其基准之下,则说明有误标,因为没有任何东西会低于基准。
步骤 5. 运行检索单元。 对于每个臂,在 k 为 5、20、100 时:
python3 locality_bench.py --mode pgvector --dsn "$DSN_ARM_A" --k 5 --out a_k5.json
python3 locality_bench.py --mode pgvector --dsn "$DSN_ARM_A" --k 20 --out a_k20.json
python3 locality_bench.py --mode pgvector --dsn "$DSN_ARM_A" --k 100 --out a_k100.json
依据该系列文章已采用的测量标准,在另一天的第二个时间窗口(或隔夜)重复完整测量。测绳(harness)在每次运行中将冷连接首次调用与汇总稳态分开记录,因而汇总混杂因素自动获得了独立的一列。
步骤 6. 运行臂 C。 如果 SaaS 商店的端点使用 PostgreSQL 线协议,则用相同的测绳指向它;否则,使用相同的试验次数和 k 值对其原生客户端进行计时,并在结果中披露客户端差异。将供应商声明的地区记录在数字旁边。
步骤 7. 填写模板并拆除。 将 Droplet 上的所有 JSON 文件复制下来,填写本文中的测量表,并从 销毁页面 销毁两个集群,以使最小套餐集群停止计费。如果当天拆除,整个运行的基础设施费用仅需几美元。
可在任何装有 Python 3 的 GPU Droplet 上运行。TCP 探测模式仅使用标准库。pgvector 模式需要一个依赖项,可通过 pip install "psycopg[binary]" 安装。依次将 --dsn 指向各个臂,并保存输出文件。
#!/usr/bin/env python3
"""
Data-locality retrieval latency harness.
Modes:
tcp : bare TCP connect probe, approximates one network RTT (stdlib only)
pgvector: timed vector similarity queries against a pgvector database
Per cell: >=75 trials after warmup discards, p50/p95/p99, cold-connection
first-call time recorded separately from pooled steady state.
Run each arm from the same GPU Droplet:
python3 locality_bench.py --mode tcp --host db-host --port 25060 --out a_tcp.json
python3 locality_bench.py --mode pgvector --dsn "$DSN_ARM_A" --k 5 --out a_k5.json
"""
import argparse, json, os, random, socket, statistics, time
def pctl(xs, p):
xs = sorted(xs)
k = (len(xs) - 1) * p / 100
f = int(k); c = min(f + 1, len(xs) - 1)
return xs[f] if f == c else xs[f] * (c - k) + xs[c] * (k - f)
def summarize(xs):
return {"n": len(xs), "p50_ms": round(pctl(xs, 50), 2),
"p95_ms": round(pctl(xs, 95), 2), "p99_ms": round(pctl(xs, 99), 2),
"mean_ms": round(statistics.fmean(xs), 2)}
def tcp_probe(host, port, trials, warmup):
times = []
for i in range(trials + warmup):
start = time.perf_counter()
s = socket.create_connection((host, port), timeout=10)
elapsed = (time.perf_counter() - start) * 1000
s.close()
if i >= warmup:
times.append(elapsed)
time.sleep(0.05)
return {"mode": "tcp", "host": host, "port": port, "summary": summarize(times),
"note": "TCP connect approximates one network round trip, no DB work"}
def pgvector_bench(dsn, k, dim, trials, warmup, table):
import psycopg # pip install "psycopg[binary]"
from psycopg import sql as psql
rng = random.Random(7)
qvec = "[" + ",".join(f"{rng.uniform(-1, 1):.6f}" for _ in range(dim)) + "]"
query = psql.SQL("SELECT id FROM {} ORDER BY embedding <=> %s::vector LIMIT %s").format(
psql.Identifier(table)
)
# cold connection: connect + first query, timed together
start = time.perf_counter()
conn = psycopg.connect(dsn)
with conn.cursor() as cur:
cur.execute(query, (qvec, k))
cur.fetchall()
cold_ms = (time.perf_counter() - start) * 1000
# pooled steady state: reuse the connection
times = []
with conn.cursor() as cur:
for i in range(trials + warmup):
q = "[" + ",".join(f"{rng.uniform(-1, 1):.6f}" for _ in range(dim)) + "]"
start = time.perf_counter()
cur.execute(query, (q, k))
cur.fetchall()
elapsed = (time.perf_counter() - start) * 1000
if i >= warmup:
times.append(elapsed)
conn.close()
return {"mode": "pgvector", "k": k, "dim": dim,
"cold_connection_first_call_ms": round(cold_ms, 2),
"pooled": summarize(times)}
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--mode", choices=["tcp", "pgvector"], required=True)
ap.add_argument("--host"); ap.add_argument("--port", type=int, default=25060)
ap.add_argument("--dsn", default=os.environ.get("PG_DSN"))
ap.add_argument("--k", type=int, default=5)
ap.add_argument("--dim", type=int, default=768)
ap.add_argument("--table", default="items")
ap.add_argument("--trials", type=int, default=75)
ap.add_argument("--warmup", type=int, default=10)
ap.add_argument("--out", required=True)
args = ap.parse_args()
if args.mode == "tcp":
result = tcp_probe(args.host, args.port, args.trials, args.warmup)
else:
result = pgvector_bench(args.dsn, args.k, args.dim,
args.trials, args.warmup, args.table)
result["timestamp"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
with open(args.out, "w") as f:
json.dump(result, f, indent=2)
print(json.dumps(result, indent=2))
if __name__ == "__main__":
main()
此脚本用于在机械臂上运行 TCP 和 pgvector 探测。
首先在每个机械臂上运行 TCP 探测,并将其 p50 放在该路径的推导基准旁边。它们之间的差距就是您的路由相对于物理极限的开销。随后在每个机械臂上分别在独立的时间窗口内以 k=5、20、100 运行两次 pgvector 模式,并填充模板表。对于调试意外路径的读者,网络性能诊断教程 介绍了此测试套件会显现但不会解释的不对称路由问题。
否。在我的测试中,NYC3→SFO3 的对等私有主机名(B2)在 TCP 和检索上与公共主机名(B1)在几毫秒内匹配。对等连接改变了隐私和出站计费;它并未让建筑物更近。
通常不值得。相对于 2 秒的生成时间,67 ms 的检索税仅占响应时间的几个百分点。索引调优和缓存可能是一周时间的更好利用。对于多跳代理 RAG,相同的税乘以跳数后,结论会倾向于更近的部署。
冷连接在第一次查询之前需要先完成 TCP 加上 TLS 握手。在约 68 毫秒的纽约到旧金山路径上,仅此设置就可能耗费数百毫秒。使用连接池; 请勿为每个请求打开新连接。
在你同时控制两端且驻留允许的情况下,答案是肯定的。在我的测试中,同一数据中心的 VPC 在池化 k=5 时延迟为 1.90 毫秒,而跨区域则为 66.97 毫秒。合规驻留可能会强制采取相反的措施:将计算迁移到数据附近,或复制一个变化缓慢的索引。
是的。测试 harness、加载 SQL 和原始 JSON 位于 anishsingh20/data-locality-tax。预期顺序和基准相同;绝对毫秒数会随路径和时间而变化。
测试 harness、加载脚本、逐个单元的原始 JSON 以及运行元数据: https://github.com/anishsingh20/data-locality-tax。
行业基准测试只关注 GPU,而忽略了管道。得出的层次结构为每个放置层级定价,复合表格展示了为什么智能体工作负载会改变结论,而测试 harness 能让你在一个下午的 GPU Droplet 上将论点转化为自己的数字。
此集群中的优化在整个路径上要么协同生效,要么共同失效。一个 温暖的提示缓存 能够节省预填充的毫秒,而错误地区的向量数据库会把这些毫秒直接退回。一个 经过调优的服务尾部 在面对 496 毫秒的地理延迟时几乎不起作用,而 推理三难题 的框架对部署的适用方式与其对服务的适用方式完全相同:您需要选择要承担的约束,本文将为您定价一种大多数团队甚至未意识到自己正在承担的约束。
经验法则是:先 colocate,再调优,最后两者都测量。
——
一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。