2025 年最让我纠结的一次存储选型,就是给 RAG 找向量存储层的时候碰上 DynamoDB 原生向量搜索正式可用。以前这套组合拳里的向量库基本是 Pinecone、Milvus、pgvector 这些专用组件,DynamoDB 在中间只是存业务元数据的角色。现在它自己能把向量索引和搜索做了,很多团队第一反应都是"能不能把组件砍掉,少养一个数据库"。但真正把它放进 RAG 架构里之前,得先把那本"三向计费"的成本账算明白——存储一个维度、写入容量一个维度、向量搜索请求单位又一个维度,三个计费口互相耦合,算漏任何一个,月底账单都会给你上一课。下面我就把这个模型拆开,再给一个 RAG 存储层到底换不换的判断思路。
这个内容适合正在做 RAG 存储选型、纠结要不要上 DynamoDB 向量搜索的工程师和技术负责人。如果你已经跑在 DynamoDB 上,但又担心向量搜索成本失控,这篇能帮你把账单里的坑提前排掉。
1. 先把三向计费这件事拆明白
1.1 三个计费维度各是什么
DynamoDB 向量搜索和传统 DynamoDB 的计费逻辑其实是一脉相承的,只是多了"索引"这个参与者。传统表是数据存储加读写容量;有向量索引的表,在传统两维之上又加了一个向量检索相关的消耗。我们行话说"三向计费",指的是下面三个口子:
- 存储费用:按 GB/月计费。注意这里不光是表里的原始数据,向量索引本身也要占空间。HNSW 索引因为是图结构,额外存储开销通常比原始向量数据高不少。
- 写入容量单位(WCU):写入一条带向量的记录时,除了写数据本身,还要同步更新向量索引。这个索引更新动作同样消耗写容量,所以单条写入的实际 WCU 消耗会明显高于普通表。
- 向量搜索请求单位(VRU):做向量搜索查询时按次计费,消耗多少和查询返回的数据量直接相关。返回的候选结果越多、每条 item 越大,消耗越高。
用一张表来对照传统 DynamoDB 和向量搜索场景下的消耗构成,会更直观:
| 计费维度 | 传统 DynamoDB 表 | 启用向量搜索的表 |
|---|---|---|
| 存储 | 数据本身 | 数据 + 向量索引结构 |
| 写入 | 写入数据消耗 WCU | 数据写入 + 索引更新均消耗 WCU |
| 查询 | 点查/扫表消耗 RCU | 向量搜索额外消耗 VRU,过滤条件还会叠加 RCU |
这就能看出来,它不是简单地在原来账单上加个"搜索费",而是三个维度同时动了。你写进一条向量,存储涨了、写容量涨了、索引还在后台持续占着存储,一鱼三吃。
1.2 为什么"三向"让成本变得不好估
我见过不少团队第一次做成本预估时,拿传统 DynamoDB 的模型去套,出来的数全都偏低,原因就在于三个维度是互相耦合的。
拿维度来说,embedding 向量的维度决定了单个 item 的存储大小,这直接影响存储费用;维度越高,写一条数据需要更新的索引边越多,WCU 消耗也随之上升;查询时返回的 top-K 条结果越多,VRU 消耗越高。三个变量互相牵扯,任何一个动一下,另外两个都会跟着变。
打个比方,这就像打车计费拆成里程、时长和调度费三部分。你只看里程觉得便宜,结果高峰期时长费一路涨,下车一看账单傻眼。DynamoDB 向量搜索也是这样,单看存储单价不贵,但把写容量的索引开销、查询的 VRU 开销叠进去,单条向量从写入到被检索的完整生命周期成本,可能比预想高 3 到 5 倍。
1.3 按需和预留模式下,向量表怎么选
DynamoDB 有两种容量模式:按需(On-Demand)和预留(Provisioned)。向量搜索表同样适用,但选型逻辑比普通表更需要注意。
按需模式的好处是弹性强、突发的灌库和查询高峰不会被打流控,坏处是单价按量计费,对持续高吞吐的业务不划算。向量搜索场景里,索引构建期往往有一个明显的写入高峰,如果你用的是按需模式,这个窗口期的 WCU 消耗会非常可观。
预留模式适合吞吐平稳的场景。但这里要小心:向量表的吞吐预估比普通表更难。因为你得把"索引更新消耗的 WCU"算进去,而它和向量维度、索引类型强相关。预留容量买少了会被限流,买多了就是白花钱。我的建议是,如果业务 QPS 和增量写入节奏比较稳定,优先预留模式,配合 Auto Scaling 兜底;如果完全无法预估,先用按需跑一段时间,观察账单里三个维度的分布,再决定要不要切。
2. 用 RAG 场景的真实参数算一笔账
2.1 先定场景参数
光说概念不过瘾,我们把一个典型的 RAG 场景参数摆出来,亲自算一遍。以下是我做选型评估时常用的一组假设,数据规模不大,但很有代表性:
| 参数项 | 假设值 |
|---|---|
| 文档切片数量 | 100 万条 |
| Embedding 维度 | 1536 维(OpenAI 常用模型) |
| 向量字节数 | 约 6KB(float32) |
| Metadata 大小 | 约 1KB |
| Top-K 返回条数 | 10 |
| 每日新增切片 | 1 万条 |
| 在线查询 QPS | 10 |
| 索引类型 | HNSW |
先说个小提示:1536 维的 float32 向量裸算就是 6KB,如果你拿 int8 或者 float16 压缩,体积和精度都会变化。这里以 float32 为例,这是最常见也是最稳的方案。
2.2 存储费用这笔账
数据存储部分:100 万条 × 7KB(向量 6KB + metadata 1KB)约等于 7GB。DynamoDB 标准存储费率大约 0.25 美元/GB/月(按 us-east-1 大概齐,其他区域略有浮动),一个月存储费用约 1.75 美元。
索引存储部分:这是最容易漏算的。HNSW 是图结构,需要存邻接关系,按我落地项目的经验,索引存储量通常是原始数据的 1.5 到 3 倍。我们折中按 2 倍算,就是 14GB,费用 3.5 美元。合计约 5.25 美元/月。
如果你觉得这个数字小到可以忽略,那就错了。同样是 100 万条数据看着不大,但当你把规模拉到 5000 万条切片,数据存储会到 350GB,索引按 2 倍算就是 700GB,一个月存储费用超过 260 美元。这不包括任何读写,仅仅是"放着不动"的成本。存储层选型的第一个坎,就是你的数据量级决定存储费量级。
2.3 写入费用:灌库和增量的隐藏成本
写入一块的坑最深。普通 DynamoDB 表写入 7KB 的 item,按 1KB 一个 WCU 算,大约消耗 7 个 WCU。但带向量索引的记录,写入时还要更新 HNSW 图,这部分额外算下来,单条写入经常要 8 到 10 个 WCU。
我们按 9 个 WCU 来算。初始灌库 100 万条,就是 900 万 WCU。按需模式约 1.25 美元/百万 WCU,一次性灌库成本约 11.25 美元。看起来还行,但注意这是一个很容易被低估的环节——因为 RAG 项目不是只灌一次就完的。文档会持续增删改,每次增量写入都在烧 WCU。
每日新增 1 万条,按 9 个 WCU 一条算,是 9 万 WCU,约 0.11 美元/天,一个月就是 3.4 美元。这个增速如果翻几倍,很快就能逼近甚至超过存储费用。更要命的是删除操作,如果做了批量清理或者高频更新,索引更新的开销会持续存在,后面排障章节我再细说。
2.4 查询费用:VRU 的消耗逻辑
查询成本的计量单位是 VRU。DynamoDB 的向量搜索按返回数据量计费,意思是你让系统返回 top-10 条,它得把 10 条 item 的数据都取出来。按每条 7KB 算,一次查询返回约 70KB 数据。VRU 单价以你账号所在区域的官方定价为准,我们按业界常见的折算粒度粗略估算,一次 top-10 查询大概消耗 8 到 10 个 VRU,成本约 0.004 到 0.005 美元。
单看也还好,但 QPS 一上来就不一样了。按 QPS=10 算,一天 86.4 万次查询,VRU 日均消耗约 700 万到 860 万。按每百万 VRU 大约 0.4 美元折算,每天查询成本就是 3 到 3.5 美元,一个月下来 90 到 105 美元。这才是真正的账单大头。
注意,这里还没算 FilterExpression。如果你在向量搜索请求里带了 metadata 过滤条件,DynamoDB 会把这些条件放在向量搜索结果返回后再处理,这个后过滤过程还会额外消耗 RCU。过滤条件再严格一点,返回结果被大量过滤掉,系统为了拿到足够的候选集,可能还会需要多次内部检索,成本进一步叠加。
2.5 和专用向量数据库的成本对比
有了上面的数据,我们把它和专用向量数据库放到一起看。
| 对比维度 | DynamoDB 向量搜索 | 专用向量数据库(如 Milvus/Pinecone) |
|---|---|---|
| 存储单位成本 | 按 GB 计费,索引存储有额外开销 | 按实例规格或 Serverless 存储计费 |
| 写入成本 | WCU + 索引更新 | 通常在实例费用内,写入吞吐受集群规模约束 |
| 查询成本 | VRU 按返回数据量计费 | 按 Peak 带宽或按检索量计费,单位成本波动大 |
| 运维成本 | 无需单独维护 | 需要维护集群或者多承担一层托管费 |
| 过滤能力 | 后过滤,严格条件下有性能损耗 | 多数支持预过滤,复杂条件更友好 |
真实结论是:如果你的业务是"查询量大、返回量小、数据规模中等",DynamoDB 按量计费可能更灵活;如果你有海量数据且长期保持高吞吐写入,专用向量库按实例打包计费反而划算。没有绝对便宜的存储方案,只有更匹配你负载模型的方案。我在很多 RAG 项目里看到,团队最后不是被功能逼走的,而是被"写一条数据要花多少隐藏成本"这本科普账劝退的。
3. 换不换存储层:RAG 负载的账不只是钱
3.1 RAG 工作负载的真正压力
聊 RAG 存储层之前,先得承认一个现实:RAG 的瓶颈通常不在向量搜索本身。我见过不少项目在向量存储上反复折腾,结果真正影响效果的是文档解析、分块策略、召回质量和重排环节。如果你的分块把上下文切得七零八落,或者 embedding 模型选得不对,换个再快的向量库也救不回来。
RAG 场景下的存储层会面对三股加压:第一是索引构建期的大量写入,一口气灌几十万条是常事;第二是查询延迟敏感,用户等着回复,检索不能拖;第三是数据持续增删改,文档库更新、切片重算,向量数据需要跟着联动。这三股压力叠加起来,才是存储选型真正要解决的问题。所以讨论"换不换",本质是讨论这三股压力,哪套系统承受起来总成本最低。
3.2 DynamoDB 留在 RAG 层的核心竞争力
DynamoDB 能在 RAG 存储层里站住脚,靠的不是向量搜索功能本身,而是它作为主数据存储的配套能力。
最值钱的是数据同源。RAG 应用往往同时要管业务状态、用户上下文、文档元数据和向量。如果这些都在 DynamoDB 里,你可以用事务保证"用户更新了文档权限,向量和元数据一起变",不用在业务库和向量库之间手动来回同步。TTL 特性也实用,聊天历史、临时会话这类带时效的数据,交给 TTL 自动过期清理,不用自己写定时任务。Streams 则可以顺势做增量同步,把数据变更事件流式推给下游。
对中小团队来说,运维红利是实打实的。少一个独立向量库,就少一套监控、少一份备份策略、少一组权限配置。如果你的核心数据量和查询压力都不大,这些隐形成本远比账单上的美元数字更值得考虑。
3.3 什么时候它明显不够用
但 DynamoDB 向量搜索也有几个绕不开的短板。
第一个是过滤能力弱。前面提过,FilterExpression 是向量检索之后的后过滤,不是先过滤。这意味着如果过滤条件太严格,可能最后返回的结果不足 Top-K,而且过滤操作本身会消耗额外的 RCU。这个短板在多模态 RAG 场景里尤其明显,比如知识库里既要存图片又要存文档,你想先按"图片类型"过滤再做相似度搜索,DynamoDB 的办法就显得笨重,检索质量和效率都会受影响。
第二个是索引控制和集群隔离能力有限。对 HNSW 的 M 值、efConstruction 这些参数,DynamoDB 基本不给你暴露,它取的是适合大多数场景的默认值。大多数场景这没问题,但你要是有低延迟高 QPS 的要求或者特殊的分布形态,就没有调优空间了。另外,专用向量库能把数据拆成多个 shard,把热点查询打散,DynamoDB 的分区设计虽说也能扛流量,但终归不是专门为向量索引优化的。
第三个是算子的丰富度。RAG 越做到后面越发现,光有向量互检索是不够的,业界很多方案会引入 BM25 稀疏检索做混合召回,再叠加重排模型。DynamoDB 没有这些算子,你要么外挂 Elasticsearch 或 OpenSearch,要么在应用层自己写一套,架构复杂度马上就上来了。
3.4 一个务实的决策框架
我自己整理过一个"要不要换"的判断清单,分享给你:
| 条件 | 建议留在 DynamoDB | 建议引入专用向量库 |
|---|---|---|
| 数据规模 | 千万级以下 | 亿级或更高 |
| 向量维度 | 1536 以内没问题 | 高维 + 大规模时更从容 |
| 查询 QPS | 中低(几十左右) | 高并发且长尾查询多 |
| 过滤需求 | 简单、低筛选率 | 复杂 metadata 过滤、高筛选率 |
| 混合检索 | 不需要或可接受外挂 | 需要 BM25 等混合召回能力 |
| 运维成本承受力 | 团队小、不想多维护组件 | 有平台团队,能承受运维复杂度 |
| 架构一致性 | 业务数据就在 DynamoDB | 已有独立的图谱/文档库要打通 |
如果你做的是 KG 知识库或基于本体(Ontology)的 RAG 方案,我的建议是架构分层。这类方案里,业务上下文和文档元数据放在 DynamoDB,图谱关系给图数据库,大规模稠密向量检索交给专用向量库,各层用事件流串联。别指望一个存储组件解决所有问题,也别因为一个组件不够全能就否定它——DynamoDB 在主数据一致性上依然是优秀的底座。
4. 如果留在 DynamoDB,这几个省钱操作值得做
4.1 数据建模上的三个控制点
决定留在 DynamoDB 之后,第一件事是重新审视数据建模,这里有三个控制点。
第一,控制 item 大小。向量是硬成本,6KB 就是 6KB,但 metadata 不是。别把一堆不太用得到的字段全塞进去。返回 top-10 时,每个 item 大一点,VRU 消耗就高一点。我的经验是:把长文本、大字段挪到 S3,DynamoDB 里只留检索必需的短元数据。
第二,控制索引类型。DynamoDB 支持 FLAT 和 HNSW 两种向量索引。FLAT 是暴力全量计算,没有图索引结构,所以索引存储几乎不增加,但查询速度慢;HNSW 查询快,但索引存储开销大。如果你的数据规模不大而且 QPS 极低,FLAT 可能是省钱的选择;数据量和 QPS 上来之后,HNSW 虽然贵,但能保证响应时间。这个选择要在建表时就定好,后面换索引类型意味着全量重新索引。
第三,对齐分区键。向量搜索之前,DynamoDB 会先按分区键缩小范围再找最近邻。把分区键设计成和你业务查询模式一致,比如按租户、类别、语言分片,能让每次搜索只在必要分区内进行,查询成本和延迟都更可控。
4.2 写入侧:让灌库和增量更平滑
写入侧的省钱策略,关键是批量化和错峰。
初始化灌库时,优先用 BatchWriteItem,一次写 25 条,减少请求次数。虽然按需模式下总 WCU 消耗不会减少,但请求级别的开销和网络往返明显下降。灌库尽量放在业务低峰期,预留模式下不会因为突发吞吐把预留容量击穿,按需模式下账单不会因为峰值翻倍而显得刺眼。
增量写入的教训是别把向量写入放在用户请求路径里。用户改了文档,应用立刻去更新向量,这种同步操作既拉高延迟又堆高账单。正确做法是把文档变更事件写进 DynamoDB Streams,由异步函数去处理向量更新,写入吞吐可控,也方便批量合并同一个文档的多次小变更。
删除和更新也要控制频率。向量索引对高频删改很敏感,每次更新都可能触发索引结构调整。能用"逻辑删除 + TTL"的场景,就别做物理删除。TTL 删除项目本身不消耗写入容量,但向量索引的清理动作和普通删除路径不同,删除高峰期还是要留意账单和存储指标的变化。
4.3 查询侧:把每次搜索的单价打下来
查询侧的成本控制,核心是"少返回"和"少计算"。
Top-K 别设太大。很多 RAG 场景其实返回 4 到 10 条足够重排用了,设成 20、50 除了让 VRU 翻倍,对最终回答质量没有明显帮助。每次多返回一条,都是实打实的计费数据量。
FilterExpression 要谨慎用。之前说过它是后过滤,条件太严会让候选集大量被丢弃,既影响召回质量,又浪费额外 RCU。如果你的业务有强过滤需求,考虑用分区键先缩小范围,或者干脆把过滤字段也作为分区键的一部分重排数据模型。
缓存热点查询。RAG 里反复被问到的问题其实很常见,高频 query 的检索结果完全可以缓存起来,TTL 设几分钟,能挡住一大部分重复计算。我见过不少团队做了缓存之后,向量搜索成本直接对半砍。别忘了给缓存设置过期时间,否则语义更新后还在返回旧结果,那就因小失大了。
4.4 账单告警与成本观测
成本观测这件事,必须从第一天就建立起来。
DynamoDB 控制台里有很多维度能看到一个表的消耗情况。你至少要看三类指标:写入容量消耗、向量搜索请求消耗、存储字节数变化。把它们和费用标签绑定,再在 CloudWatch 里设告警,比如单日 VRU 消耗超过设定阈值就发通知。这样即使某个晚上有用户疯狂调用,或者调试脚本反复灌库,账单异常也能第一时间被发现。
Cost Explorer 里记得开启表级别和标签级别的拆分。我见过一个项目所有 DynamoDB 表的向量搜索费用混在一条里,根本看不出是哪个业务线烧的。分标签之后,谁的负载异常谁负责,成本归因才清晰。并且建议每隔一两个月复盘一次:如果某张表的向量搜索成本连续三个月环比增长超 20%,大概率是数据规模或查询模式在膨胀,这时候再翻出来做一次选型评估。
5. 常见问题与排查技巧实录
5.1 为什么账单比我预期的贵
很多团队第一次看到启用向量搜索后的账单都会问这个问题。最常见的原因有三个:一是索引存储被低估了,HNSW 的存储开销没算进去;二是写入 WCU 被低估了,带索引更新的单条写入消耗比普通表高;三是 FilterExpression 的后过滤产生了隐藏 RCU 消耗。
自查路径其实简单:去看 CloudWatch 里这张表的存储字节数趋势,如果明显高于你把数据 size 估算出来的值,就是索引占空间。再看流量指标里的写入消耗和搜索消耗分布,哪一个和预期偏差最大,问题就出在哪一个上面。
5.2 向量搜索延迟偏高怎么查
延迟问题从三个方向排查。
第一,看是不是冷启动。新建的表第一次大量查询,底层需要预热,延迟波动正常;第二,看分区热度分布。如果所有查询都打在同一组分区键上,热点分区的吞吐会受限,导致延迟上扬;第三,看索引类型。FLAT 索引在数据量大了之后,每次查询都是全量计算,延迟飙升是必然的,这种情况要么数据归档缩量,要么换 HNSW。还有一个小细节,Top-K 设太大也会让响应体变大,网络传输时间跟着涨,即使计算端很快,整体延迟也慢。
5.3 删了数据账单却没有降
这个是很多人的困惑:明明清理了大量旧向量,存储账单和查询成本纹丝不动。原因有两个方向。
一个是索引结构并不会立即释放空间。HNSW 这种图结构在删除时通常做标记删除,底层空间会延迟合并回收,存储指标不会立刻掉下来;二是删除动作本身会触发索引更新,在删除高峰窗口反而会看到写入容量消耗升高。如果你的场景里大量删除很常见,建议在低峰期集中清理,不要用高频小批删。同时留意 TTL 删除的索引清理行为,必要时主动查一下存储指标是否匹配预期。
5.4 问题速查表
| 症状 | 可能原因 | 排查方法 |
|---|---|---|
| 账单高于预期 | 索引存储超预期 / FilterExpression 产生额外 RCU / QPS 被外部调用放大 | 检查存储趋势、查询消耗分布 |
| 搜索延迟高 | 冷启动 / 分区热点 / FLAT 索引 / Top-K 过大 | 看延迟曲线、分区热度、索引类型 |
| 删除后存储未下降 | 索引延迟回收 / 标记删除 | 观察存储指标,低峰期集中清理 |
| 过滤后结果不足 | FilterExpression 后过滤导致候选被大量丢弃 | 用分区键缩小范围,或重排数据模型 |
| 灌库被限流 | 预留容量不足 / 突发吞吐击穿预留 | 开 Auto Scaling 或临时提升预留容量 |
5.5 我的组合拳方案
说到底,我不想把 DynamoDB 和专用向量库放在对立面。更成熟的做法是打成组合拳:热数据和高频访问的向量放 DynamoDB,利用它的低延迟、TTL 和事务能力;大规模冷数据或者对过滤/混合检索要求高的部分,放专用向量库。两者之间用 DynamoDB Streams 或 EventBridge 做增量同步,形成一个分层存储架构。
这样既保留了 DynamoDB 在主数据一致性上的优势,又让向量检索回到它最擅长的引擎里。让每个组件做它最擅长的事,而不是让一个组件硬扛所有需求。
最后再分享一个小技巧:别在第一次选型时就追求"一步到位"。先拿真实数据跑一批量级的压测,同时记录账单成本曲线,用账单数据反推架构决策,比任何功能对比表都靠谱得多。