High-Throughput, Cost-Effective Billion-Scale Vector Search with a Single GPU
可以。先不要陷进 CUDA kernel 和实验参数里,这篇论文真正需要先抓住的是它的系统观念变化:
GustANN 认为:在“追求极高吞吐量”的 SSD 图 ANN 场景里,瓶颈不一定是 SSD,而可能是 CPU 根本产生不了足够快的图搜索计算与 I/O 请求。于是它把 graph traversal 整体搬到 GPU,只让 CPU 做 I/O 搬运辅助。
论文是 GustANN: High-Throughput, Cost-Effective Billion-Scale Vector Search with a Single GPU,SIGMOD 2025。
1. 一句话理解 GustANN
它的硬件结构可以概括成:
┌──────── GPU ────────┐
│ PQ vectors │
Query ──> Pivot ──> │ graph traversal │
│ distance / sort │
│ dedup / next node │
└─────────┬───────────┘
│ 需要 node u
↓
SSD ──4KB page──> CPU DRAM ──record──> GPU
~60 GB/s ~<1KB
论文做的不是:
CPU 搜索 + GPU 算距离
而是:
GPU 搜索 + CPU 帮 GPU 搬 SSD 数据
作者称其为:
GPU-centric, CPU-assisted architecture。
这是整篇论文最关键的设计定位。
2. 为什么作者觉得 DiskANN 这一类系统不够好?
建议你重点看论文 §3.1,PDF 第 5–6 页。
传统认识通常是:
DiskANN
CPU computation 很快
↓
SSD random I/O 很慢
↓
SSD 是瓶颈
所以 DiskANN 等工作大量关注:
-
减少 SSD I/O;
-
beam search;
-
latency hiding;
-
cache;
-
更好的图结构。
但 GustANN 说:
这个结论主要适用于 latency-critical workload。
如果目标变成:
几十万 QPS
问题发生变化了。
论文测得 DiskANN:
-
单 worker 大约:
-
1/6时间 computing -
5/6时间等 SSD;
-
-
乍一看明显是 SSD-bound。
但是作者做了一个很重要的思想实验:
假设 SSD I/O latency 完全可以隐藏。
那么 CPU 可以把原来 1/6 的计算时间扩展到全部时间:
DiskANN 实际:
CPU compute : 1
SSD wait : 5
perfect overlap 后:
CPU 可以做约 6× computation
→ 约 6× I/O throughput
他们实际 DiskANN 只有大约:
6 GB/s
那么理想情况下也只有:
6 × 6 GB/s ≈ 36 GB/s
但 6 块 SSD 的理论带宽是:
6 × 10 GB/s = 60 GB/s
于是即使 I/O 完全不等待:
CPU 依然喂不满 6 块 SSD。
作者进一步估算,他们的 56-core CPU,大约只能支撑 3.6 块 SSD 的计算需求。
3. 这其实是论文最重要的 insight
这里非常值得和你之前讨论 DiskANN 的问题联系起来。
GustANN 并没有说 SSD 随机访问不重要。
它说的是:
latency-oriented
单 query:
compute → SSD read → compute → SSD read
↑
latency 大
所以 SSD latency 是核心问题。
throughput-oriented
同时跑:
40,000 queries
大量 query 可以覆盖 I/O latency:
Q1: compute ---- IO ----
Q2: compute ---- IO ----
Q3: compute ---- IO ----
...
此时问题变成:
你的 CPU 能不能足够快地执行图遍历、距离计算、candidate management,从而不断生成 SSD I/O?
GustANN 的答案是:
CPU 不够。
所以需要 GPU。
这就是这篇论文与很多 DiskANN-style 工作最大的视角区别。
4. 那为什么不能直接让 GPU 搜索 SSD?
这就是论文的第二层问题。
已有两种架构。
A. CPU-centric, GPU-assisted
例如:
CPU:
graph traversal
candidate management
SSD access
│
↓
GPU:
distance calculation
论文认为这不解决问题,因为:
graph traversal 仍然在 CPU。
CPU 仍然是 throughput bottleneck。
B. GPU-only
变成:
GPU
├ graph traversal
├ distance
├ candidate management
└ direct SSD access
例如 BaM / GDS 这类 GPU direct storage。
这解决 CPU 计算瓶颈,却引出了两个新瓶颈:
-
GPU memory
-
SSD → GPU PCIe bandwidth
所以 GustANN 的三个核心设计,正好是一一解决这些问题。
5. Design 1:Memory-Efficient GPU Graph Traversal
这是 §4.2,也是算法层面最有技术含量的一部分。
传统 ANN 搜索都会维护:
visited set
例如:
hash table
Bloom filter
bitmap
原因很简单:
假设展开节点 u:
neighbors:
A B C D E
其中 C 之前已经访问过:
visited(C) = true
那么:
不要再算 PQ-distance(C, q)
CPU 上这是很合理的:
用 memory 换 computation。
但 GPU 上作者反过来了
论文提出一个非常 GPU-oriented 的思想:
GPU 上少做几个 distance computation 未必能让程序更快。
因为 GPU 是 SIMT:
warp = 32 threads
如果:
thread 0:发现 duplicate,不计算
thread 1~31:都计算
thread 0 实际上也得等。
所以作者干脆:
先把 duplicate 也算了。
即:
传统:
deduplicate
↓
distance
↓
insert
GustANN:
distance
↓
sort
↓
deduplicate
也就是论文非常核心的一句话:
Sort first, then deduplicate.
6. 为什么这能省这么多显存?
传统 visited table 至少需要:
L×R
假设:
L = 300
R = 128
节点 ID 4 bytes:
300×128×4≈150KB
考虑 hash table/Bloom filter load factor 等,实际可能:
>300 KB/query
而 GustANN 目标是:
~40,000 concurrent queries
于是:
300KB×40000≈12GB
光 visited table 就差不多 12 GB。
A100-40GB 上还有:
1B vectors × 32 B PQ
≈ 30 GB
所以根本放不下。
GustANN 怎么 dedup?
先:
new neighbors
↓
PQ distance
↓
sort
然后 candidate array 已经按照距离排序。
对于 duplicate ID,它们会被检测出来,再通过 GPU warp primitives:
compare
↓
ballot / broadcast
↓
bitcount
↓
prefix-sum-like position calculation
↓
compact
完成并行去重。
论文 Figure 5(PDF 第 11 页)就是这个过程。
最终:
BANG ≈ 480 KB/query
GustANN ≈ 40.22 KB/query
大约:
11.93× 更省 per-query GPU memory。
这使 40K concurrent queries 成为可能。
7. Design 2:CPU-Assisted Transfer
我认为这是整篇论文中最漂亮的系统设计。
先看硬件。
论文机器:
6 × PCIe 5.0 SSD
↓
aggregate ≈ 60 GB/s
A100 PCIe 4.0 ×16
↓
GPU inbound ≈ 24 GB/s
于是如果:
SSD → GPU
直接搬:
60 GB/s
↓
24 GB/s bottleneck
你有 6 块 SSD 也没意义。
论文 Figure 6 专门画了这个瓶颈。
8. 关键观察:GPU 根本不需要整个 SSD page
SSD 最小读取单位:
4 KB
但 graph node record 大约:
vector
+
neighbor IDs
例如 DEEP1B:
vector:
96 × float
= 384B
neighbors:
128 × int
= 512B
total:
896B
也就是说:
SSD read = 4096B
实际需要 = 896B
只需要:
896/4096≈22%
所以 GustANN 做:
4096 B
SSD ───────────────→ DRAM
│
│ 896 B
↓
GPU
而不是:
4096 B
SSD ───────────────→ GPU
这就是所谓:
CPU-assisted selective transfer
DRAM 在这里本质上就是:
bounce buffer
不是用来存整个 index。
9. 为什么绕 CPU 一圈反而更快?
表面看:
SSD → DRAM → GPU
明显比:
SSD → GPU
多了一跳。
但问题在于瓶颈的位置不同。
Direct:
SSD 60GB/s
↓
GPU PCIe 24GB/s
↓
只能使用 ~24GB/s
GustANN:
SSD
│ 60GB/s
↓
DRAM
│
│ selective ~25%
↓
GPU
≈15GB/s
满足:
15<24GB/s
于是 GPU inbound PCIe 不再成为瓶颈。
所以这里是典型的:
多走一步,但少搬 75% 数据。
结果实验中:
GustANN vs BaM-ANN
≈2.50–2.71× throughput
这部分对应 PDF 第 12–13、19–20 页。
10. Design 3:Pivot Search
第三个问题很容易被低估:
为什么 RAID-0 已经把 page 均匀条带化到 6 块 SSD,仍然会负载不均?
作者认为原因来自:
single entry graph search
DiskANN-style graph:
entry
●
/ | \
● ● ●
...
所有 query 都从:
同一个 entry point
开始。
于是前几轮都会访问:
entry 周围的一小片 graph region
而这一片 region 的 node:
可能并没有均匀落在 SSD1~SSD6 上。
于是:
SSD1: ███████████
SSD2: ███
SSD3: █████
SSD4: ██
...
形成作者所谓的:
micro-scale load imbalance。
11. Pivot graph 是怎么解决的?
GPU 上额外放一个非常小的 graph:
完整 dataset
1 billion vectors
↓ random sample
~1 million vectors
↓
pivot graph
query 先:
Query
↓
pivot graph search
↓
找到一个 query-specific pivot
↓
从这个节点进入 SSD graph
于是不同 query:
Q1 → region A
Q2 → region F
Q3 → region C
Q4 → region A
...
不再全部拥挤在:
single entry region
它带来两个效果:
-
SSD load balance;
-
入口本身离 query 更近。
论文实验:
throughput:最多 +1.50×
SSD bandwidth:最多 +1.23×
而且 6 个 SSD 的 tail latency divergence 明显减小。
对应 Figure 12、13,PDF 第 20 页。
12. 不过 Pivot Search 本身并不是完全新的
作者自己也承认:
Starling 有:
navigation graph
也是:
small graph
→ 找一个更好的 SSD search entry
区别是论文宣称:
Starling
主要目的:
减少 SSD I/O
GustANN
主要目的:
multi-SSD load balance
而且:
Starling:CPU search navigation graph
GustANN:GPU search pivot graph
所以这里更像是:
已有 navigation idea 在 GPU + multi-SSD throughput 问题上的重新定位。
这是阅读这篇论文时需要保持清醒的一点。
13. 整个 Query 到底怎么跑?
理解这一段后,整篇论文基本就通了。
单个 query:
① GPU pivot search
↓
找到 entry node
② GPU:
选择当前 exploring node u
↓
③ CPU:
向对应 SSD 发 4KB read
↓
SSD → DRAM
↓
从 page 提取 node record
↓
DRAM → GPU
④ GPU:
full-distance(u)
neighbor PQ-distance
sort
dedup
update candidate set
选择 next exploring node
↓
⑤ 回到③
注意:
CPU 并不负责 graph traversal。
CPU 基本只是:
I/O scheduling
SSD queue management
memory copy
batch dispatch
所以论文声称只需要:
8 CPU cores
其中:
2 threads:query / GPU / SSD dispatch
6 threads:6 SSD I/O queues
14. 单 query 还是串行,那吞吐量怎么上去?
这里有一个重要设计:
inter-query pipelining
单 query:
SSD → GPU → SSD → GPU → SSD → GPU
有严格 dependency:
不知道 next node
→ 就不知道下一次读哪个 SSD page
所以无法把单 query 变成完全流水。
GustANN 改为许多 mini-batch:
time →
Batch A:
SSD ███
GPU ███
SSD ███
Batch B:
SSD ███
GPU ███
Batch C:
SSD ███
GPU ███
于是:
单 query 内不能 pipeline,queries 之间可以 pipeline。
这和你之前讨论 PipeANN / FlowANN 时其实是一个很值得注意的共同模式:
用不同 query / batch 的独立性去填满不同硬件阶段。
但 GustANN 的阶段是:
SSD/CPU transfer
↕
GPU graph search
而不是简单的 CPU ↔ SSD compute-I/O pipeline。
15. 实验结果怎么看?
论文最核心数字不用全记,只记四个。
SSD utilization
最高:
86.7%
6 块 SSD × 10 GB/s:
理论 ~60GB/s
实际 ~52GB/s
vs DiskANN
billion-scale:
SIFT1B : 7.81×
DEEP1B : 6.98×
vs GPU systems
论文报告至少:
2.50× throughput
Cost-effectiveness
以 $ / QPS:
vs CPU+GPU:2.62× better
论文摘要还给出了单 GPU + 6 SSD:
247K billion-scale vector searches/s
的代表性结果。
16. 但这篇论文有一个非常重要的代价
latency
GustANN 是非常明确的:
Throughput-first
要到最大 throughput:
latency ≈ 140 ms
如果限制:
latency < 25ms
那么只能获得:
约 1/5 peak throughput
所以它不是要取代传统低延迟 DiskANN。
作者的 argument 是:
RAG:
ANN retrieval ~100ms
LLM prefill/generation
~100ms–1s
所以 ANN 多几十毫秒没那么致命。
换句话说:
GustANN 本质上是在用 batching latency 换 hardware utilization。
17. 这篇论文真正的三个贡献,我会这样评价
如果去掉作者的包装,我认为可以压缩成:
| 设计 | 本质 |
|---|---|
| Sort-then-dedup | 用 GPU 的冗余计算换显存 |
| CPU-assisted transfer | 用 DRAM 做 page → record 过滤,减少 GPU PCIe 流量 |
| Pivot search | 把 query 从单入口热点区域打散到整个 graph |
其中我认为 novelty / systems insight 强度大致是:
CPU-assisted selective transfer
>
GPU memory-efficient traversal
>
pivot search
Pivot graph 的概念本身并不新;它主要是找到了一个新的系统问题——multi-SSD tail load imbalance——并把 navigation graph 用到了这里。
18. 它与你最近在看的 FlowANN / PipeANN 有什么区别?
这里先给你一个粗定位,后续我们可以专门比较。
PipeANN / 类似设计
主要问题通常是:
CPU computation
↔
SSD I/O
怎么 overlap。
GustANN
更进一步认为:
CPU computation 本身就不够
所以直接变成:
GPU traversal
↔
SSD
然后发现新的:
SSD aggregate bandwidth
>
GPU inbound PCIe bandwidth
再引入:
SSD → CPU DRAM → GPU
所以有一种很有意思的演化:
DiskANN
SSD latency bottleneck
↓
pipeline
↓
CPU throughput bottleneck
↓
GPU
↓
GPU PCIe bottleneck
↓
CPU-assisted selective transfer
每解决一层瓶颈,下一层瓶颈就冒出来。
这其实就是这篇论文最值得学习的系统研究思路。
19. 我建议你按这个顺序读
不要从第一页顺读到第 27 页。最高效的顺序是:
-
§3.1–3.3:Motivation
先理解为什么 CPU 变成 bottleneck。 -
Figure 4 + §4.1
把 GustANN 总架构彻底搞明白。 -
§4.3 CPU-Assisted Transfer
这是最关键、最好理解的设计。 -
§4.2 GPU Graph Traversal
再深入 sort-before-dedup 和 warp-level dedup。 -
§4.4 Pivot Search
理解 single-entry → micro-scale imbalance。 -
§5.3 Breakdown
看三个设计到底各贡献多少,而不是先看 Overall Performance。 -
最后看 §5.4–5.6
重点寻找适用边界和 weakness。
如果把这篇论文压成一张“脑内结构图”,就是:
High-throughput SSD ANN
│
CPU 算力不够
│
▼
GPU graph search
│
┌───────────────┼────────────────┐
│ │ │
GPU memory PCIe inbound SSD imbalance
│ │ │
▼ ▼ ▼
sort then dedup SSD→DRAM→GPU pivot search
│ │ │
└───────────────┼────────────────┘
▼
40K concurrent queries
│
inter-query pipeline
│
▼
~87% SSD utilization
下一步最值得做的是逐行拆 §3.1 的“CPU 为什么会成为瓶颈”,因为这恰好会触及你之前对 DiskANN“到底应该减少 SSD I/O,还是应该高度并行 I/O”的那个问题;GustANN 给出的答案比表面上的“GPU 比 CPU 快”要深得多。