1. 这场成本讨论的起点:看到账单翻倍的那一刻
前几天有个做RAG项目的朋友找我吐槽,说他的项目跑了大半年一直很稳,直到他为了省事把向量索引开进了DynamoDB,上个月的账单直接让他从椅子上弹了起来。他很困惑:DynamoDB原生向量搜索不是AWS官方推出的功能吗?按说应该比自己运维一套向量数据库省钱省心,怎么反而更贵了?
这个问题问得特别好。很多人在评估“DynamoDB原生向量搜索”的时候,注意力全放在“原生”两个字上,下意识觉得这意味着低成本、免维护。但真正落地之后,账单结构会告诉你另一套故事——它本质上是一套复合架构,DynamoDB负责数据主存储和读写接口,后台还连着一套托管的向量检索引擎。这套架构的计费是“三向”的,不是简单的一个存储单价乘容量。
这篇文章,我就用实际算账的方式,把DynamoDB原生向量搜索的计费模型彻底拆开:三个方向各花什么钱、每个方向的钱是怎么涨上去的、RAG场景下这套方案和独立向量数据库比到底是省钱还是费钱、以及最重要的——你的RAG存储层到底要不要换。
适合谁看?正在用DynamoDB存RAG数据、纠结要不要开向量索引的;已经开了向量索引但账单看不懂的;以及在大厂做架构选型需要给领导一个成本依据的。
2. 原生向量搜索的底层架构:你的数据其实跑了双份
要算清楚钱,第一步不是看价目表,而是搞明白DynamoDB原生向量搜索在物理上到底做了什么。
2.1 表面上你只调了DynamoDB API,后台是一个组合体
DynamoDB原生向量搜索,官方叫Vector Search for Amazon DynamoDB,是在2024年推出的。它的使用方式确实很“原生”——你把向量字段写进DynamoDB表,然后调用Query API传一个向量进去,就能做相似度检索。体感上就像DynamoDB自己长了向量搜索能力。
但实际上,这套能力是基于OpenSearch Serverless的托管向量索引实现的。你的向量数据会被同步到一个OpenSearch Serverless的Collection里,DynamoDB负责事务性读写和主数据存储,OpenSearch负责向量近邻搜索。用户层面只有一套API,底层却是两套存储引擎在协同工作。
用一个生活化类比来说:DynamoDB是你家的家庭账本,负责记录每一笔开支;OpenSearch Serverless是一个专门练就“快速翻账本找相似条目”本事的助理。助理不负责记账,但他手里有一份账本的副本,专门用来快速检索。你说“帮我找和这笔开销最像的上十笔”,助理在副本上刷刷翻完,再回头找主账本拿完整信息。
这个架构有个天然的推论:凡是写入DynamoDB并开启向量索引的数据,实际存储了两份。一份在主表,一份进了向量索引。即便你删掉主表数据,向量索引那边还有副本,反向同步也需要时间。所以你付的钱,从物理意义上就是两份存储的钱加上同步的钱。
2.2 索引构建方式决定了检索质量和成本
OpenSearch Serverless这边的向量索引不是只此一种,它支持三种索引类型:
| 索引类型 | 全称 | 核心特点 | 适合场景 |
|---|---|---|---|
| Flat | 暴力精确索引 | 全量计算,召回最精确,但存储和计算开销最大 | 数据集小(十万级以内)、对精度要求极高的场景 |
| HNSW | 分层可导航小世界图 | 近似最近邻检索,速度快、召回率高,需要调参数 | 绝大多数生产场景,百万级甚至千万级向量推荐 |
| Sparse | 稀疏向量索引 | 适合关键词类匹配,资源占用更低 | 混合检索场景,特别适合RAG里做关键词+语义双路召回 |
HNSW是生产中最常用的选择。它有两个关键参数需要你建索引时指定:m代表每个节点最多连接数量,efConstruction代表构建索引时的动态候选集大小。m越大,图连接越密,召回越准,但索引体积和构建内存开销同步上涨;efConstruction越大,构建质量越高但构建时间越长。我当时做第一个项目时因为贪召回率,把m调到了64,结果索引构建直接从30分钟变成3个小时,账单也跟着涨。后来调回16,召回率只降了不到2%,成本却省了将近一半。
2.3 DynamoDB Streams在后台默默搬运数据
向量索引里的数据不是凭空出现的,它是通过DynamoDB Streams把主表变更事件流式同步过去的,期间通常还会有一个Lambda或EventBridge Pipe来负责把流事件转换成OpenSearch的写入请求。
这意味着每个写操作实际上串联了三个服务:DynamoDB主表写入、Streams事件产生、Lambda计算执行、OpenSearch索引写入。任何一个环节有数据量波动,都会同时带动三份计费跳动。很多人开了向量索引之后发现,不光OpenSearch那边有费用,DynamoDB Streams的读取费用和Lambda的调用费用也跟着涨了,原因就在这里。
这个架构还有个经常被忽视的点:Streams和Lambda是异步链路,如果写入高峰期OpenSearch索引速度跟不上,Lambda会重试、堆积、甚至丢事件。数据量大了之后,你需要关注同步延迟和失败重试的监控告警,这部分的运维精力成本,虽然是隐性的,但确实存在。我在一个每日新增2万条文档的项目里,就遇到过OpenSearch集合的写入容量自动扩展跟不上,导致同步延迟达到40分钟的情况——用户刚写入的文档搜不到,对RAG体验来说几乎是致命的。
3. 三向计费拆解:每一分钱到底花在了哪
现在进入正题。这个“三向计费”是我自己总结的叫法,因为DynamoDB原生向量搜索的成本结构可以分为三个相互独立的计费方向,任何一个方向的数据量上涨都会带动整体账单非线性增长。
3.1 第一向:DynamoDB侧的存储与读写费用
这一向你并不会陌生,它的计费模型和普通DynamoDB完全一样:
- 存储费:按GB按月计费,标准存储当前大约0.25美元/GB/月;
- 写入容量单位(WCU):每个WCU每秒可写1KB,按使用量累加;
- 读取容量单位(RCU):每个RCU每秒可读4KB,按使用量累加。
但开了向量搜索后,DynamoDB侧的费用会发生变化。首先,向量字段通常都比较长,一条1536维的浮点向量占用的空间是6KB(1536×4字节),加上metadata和其他字段,一条记录轻松超过10KB。而普通文档类数据单条可能只有几百字节。存储费用是跟着数据大小线性涨的,向量数据的存储成本天然就是普通结构化数据的十几倍。
另一个容易被忽略的变化是:为了在Streams事件中携带向量字段,每次写入的实际数据量也会增大,WCU消耗随之上升。如果向量字段达到6KB,那么每写一条记录就要消耗6个WCU(每1KB一个),单价按量付费大约是0.00125美元/WCU,如果每天写2万条,一个月光写入就是45美元——这笔钱在没开向量搜索之前几乎不存在。
3.2 第二向:OpenSearch Serverless的计算与存储费用
这一向是账单里涨幅最凶的部分,也是大多数人看不懂的部分。OpenSearch Serverless的计费单位是OCU(OpenSearch Compute Unit),每个OCU包含2GB内存和对应的vCPU资源,按OCU小时计费。官方单价约0.352美元/OCU/小时(不同区域会有浮动)。
它有两个独立的计费通道:
- Indexing OCU:摄入数据写入索引时消耗的计算容量;
- Search OCU:执行查询时消耗的计算容量。
这两个通道完全独立,意味着你就算半夜没有写入流量,只要还在跑着,Search OCU可能依然是保留数量在计费。更要命的是,OpenSearch Serverless的自动扩缩容逻辑是按“发生过使用的最大值”和“预留容量”来算的,不是按实时利用率算的。我见过一个项目,平时查询QPS不到5,只有每天早上有一波批处理导致搜索峰值冲到50,然后整整一个月账单都按峰值50的Search OCU容量来扣钱。
索引存储也单独收费,大约0.35美元/GB/月。HNSW的索引体积通常是原始向量的1.2到1.5倍,100万条1536维向量原始数据大约6GB,索引体积会膨胀到8GB左右,存储费每月约2.8美元。听着不贵,但大头在计算上,下面算给你看。
3.3 第三向:Streams、Lambda和数据传输的隐性成本
第三向是最多人翻车的地方,因为它的费用分散在DynamoDB Streams、Lambda和跨服务数据传输三个地方,账单上不会汇总成一行“向量同步费用”,而是散落在各个服务条目里,很难一眼发现。
- Streams读取:DynamoDB Streams的API调用按读取次数计费,每次读取会返回最大1MB的流记录,如果开启向量索引后每条流记录因为携带向量字段变得很大,读取次数会相应增加;
- Lambda调用与运行时长:用于同步数据的Lambda一般按调用次数和运行时长计费,每100万次调用大约是0.2美元加0.04美元/GB/秒的花费。2万条/日的写入量不算多,一个月产生的Lambda费用大约在20-30美元之间,看着不起眼,但它是一个持续每月都在扣的费用;
- 跨服务数据传输:从DynamoDB Streams到Lambda再到OpenSearch,如果跨可用区,还会产生数据传输费,这个通常能通过把服务部署在同一可用区来规避,但很多人根本不会关注这点。
这三向费用叠加起来,才是DynamoDB原生向量搜索的真实成本。单独看任何一项,单价都很低;全部加在一起,就不再是“便宜”能形容的了。
3.4 给一个真实规模算总账
用100万条1536维向量(OpenAI text-embedding-3-small的常见输出维度)、每条记录连带metadata约8KB、每天新增2万条、查询QPS为10、开启HNSW索引的场景来算月度成本:
| 费用项 | 计算方式 | 月成本估算 |
|---|---|---|
| DynamoDB存储 | 100万条×8KB≈8GB,约0.25美元/GB | 2美元 |
| DynamoDB写入WCU | 2万条/日×8KB≈16万KB/日,需16个WCU持续一小时 | 约45美元 |
| DynamoDB读取RCU | 查询10 QPS×8KB读取 | 约18美元 |
| OpenSearch索引存储 | 100万条向量8GB×1.3膨胀系数≈10.4GB | 约3.6美元 |
| OpenSearch Indexing OCU | 2万条×8KB/日写入,需要至少1个OCU持续运行 | 约84美元 |
| OpenSearch Search OCU | 10 QPS持续,通常需要2个OCU保温 | 约168美元 |
| Streams + Lambda | 2万条/日,100万次级别调用 | 约25美元 |
| 合计 | 约345.6美元/月 |
这个数字意味着什么?对比一个50美元/月就能搞定的基础版Pinecone或Qdrant Cloud Starter实例,DynamoDB原生向量搜索在同等规模下并不便宜——甚至可以说,在纯向量检索这个维度上,它比主流专用向量数据库的入门档要贵不少。
4. RAG存储层到底要不要换:决策矩阵比盲目迁移重要
算完账,很多人会下意识说“那就换呗”。但现实没这么简单。成本只是存储选型的一个维度,RAG项目的存储层是否该换,取决于你的数据规模、访问模式、工程约束和团队维护能力共同决定的综合判断。
4.1 先分清你的RAG属于哪种类型
不是所有RAG项目都需要一套独立的向量数据库。我见过很多团队一股脑上了Milvus,最后发现自己的数据总量不到10万条,查询QPS个位数,运维成本远高于收益。RAG项目大致可以分为三档:
| 项目规模 | 典型特征 | 合适的存储方案 |
|---|---|---|
| 轻量级 | 数据量<10万条,单机可跑,QPS低,团队人手少 | 继续用DynamoDB原生向量搜索,或直接上pgvector |
| 中量级 | 数据量10万~500万条,有稳定的在线流量,需要混合检索 | DynamoDB原生向量搜索可用,或用托管向量库(Pinecone等) |
| 重量级 | 数据量>500万条,高QPS,毫秒级延迟硬性要求,需要复杂过滤 | 独立向量数据库专用集群,调整参数空间更大 |
这个分档不是拍脑袋定的,核心逻辑是:向量搜索领域的性能瓶颈集中在索引构建、内存占用和查询过滤上,轻量级项目用DynamoDB原生方案自然够用;重量级项目则吃集群调优和精细控制,托管方案给不了那么大的自由度。
4.2 “要不要换”的核心判断维度
除了规模,还有四个关键维度值得拿来做决策:
第一是查询复杂性。如果你的RAG检索不只依赖向量距离,还需要在metadata上做复杂的multi-attribute过滤、布尔组合过滤甚至按业务字段做时态筛选,DynamoDB原生向量搜索的过滤能力会受限——它会把过滤条件下推给向量引擎,但复杂过滤会显著拖慢查询速度。这种情况下,专用向量数据库配合各自的Filter机制会更游刃有余。
第二是延迟敏感性。这里需要区分是真敏感还是伪敏感。如果用户点一下按钮等1秒就流失,那延迟敏感;如果只是后台批处理生成摘要,那1秒完全无所谓。DynamoDB原生向量搜索因为多了中间同步层和OpenSearch跳转,P95延迟通常比专用向量库高20%-40%。我的经验是:如果目标延迟是50ms以内,考虑换;如果能接受200ms以上,DynamoDB原生方案完全没问题。
第三是混合检索需求。RAG最近的热搜里就能看到rag框架、rag智能体、rag检索增强这些词,说明检索质量成了RAG落地的核心痛点。混合检索(向量语义检索+关键词BM25检索)在当前RAG实践里是显著提升召回效果的做法。DynamoDB原生向量搜索在这个方面支持度偏弱,能跑但不是阵地,需要额外拼接其他服务。如果你打算做重度的混合检索,独立向量数据库大概率更适合你。
第四是成本可预测性。OpenSearch Serverless的OCU扩缩容逻辑天然带有波动性,流量毛刺会导致账单非线性上涨,预算负责人如果对成本波动容忍度很低,专用向量库的固定月费模式会让人睡得踏实得多。
4.3 一个关键认知:换不换存储层和是否继续用DynamoDB并不冲突
很多团队在犹豫“要不要换”的时候,陷入了一个二元思维:要么全用DynamoDB原生向量搜索,要么全换成独立向量数据库。但实际上还有一个中间方案:继续让DynamoDB担任主数据存储与事务源,并把向量同步到外部的专用向量库,做双写。
这个方案的好处非常明显:
- 保留DynamoDB的事务性读写、审计、备份恢复能力;
- 向量搜索交给专用引擎,享受更成熟的调参空间和稳定性;
- 迁移风险低,DynamoDB的Streams机制已经天然提供了CDC能力,不用改业务代码太多。
我在一个金融知识库项目里用的就是这个思路:业务读写全走DynamoDB,Streams双写到Qdrant和OpenSearch,DynamoDB侧的向量索引干脆没开——因为确认了Qdrant对这种中等规模的RAG场景无论是成本还是性能都已经更优。
4.4 什么时候坚定不换
反过来,也有两类场景我建议坚定留在DynamoDB原生向量搜索方案里:
一是数据强一致和审计要求极高的场景。DynamoDB的主表就是事实源,向量索引只是派生物,不会有两套系统对账不一致的苦恼。如果你所在的业务要求“写入即可查”且“删除必须立刻反映到检索结果”,DynamoDB原生方案在一致性层面比外部向量库要好处理得多。
二是团队DynamoDB技术栈已经成熟且不想引入新运维负担的场景。外部的组件就多一个故障点,多一个需要备份和监控的东西。小团队没有专职的数据库运维,留在原方案里少操心,这笔隐形成本往往比几十美元账单更值钱。
5. 不换方案的前提下,成本治理还能怎么救
如果说你评估了一圈,发现自己的场景确实更适合留在DynamoDB原生向量搜索上,那接下来要做的就是把这套方案的成本往合理区间压。以下是我在几个项目里实际验证过有效的治理手段。
5.1 写入策略:能用批量就别用逐条
向量搜索的Indexing OCU对写入模式极其敏感。同样每日2万条增量,均匀分布在一天里逐条写入,Indexing OCU就会持续有一个OCU在烧钱;但如果集中到每小时一个批次批量写入,把写入压缩进一段高吞吐的短窗口里,其他时间让OCU缩容,成本差距可能达到30%-50%。
具体做法是:把实时性要求不高的文档处理链路改成定时批处理。比如每30分钟拉取一次待处理的文档,批量生成embedding,写入DynamoDB时采用BatchWriteItem而不是单条PutItem,向量Streams那边同步链路会一次性消费大批量事件,索引构建的吞吐利用率显著提升。
实时性至上的场景另当别论,但是AI知识库的文档增量在绝大多数场景下其实并不需要秒级可见。为了所谓实时而牺牲几十美元成本,不划算。
5.2 数据降维与量化:比你想的更值得做
OpenAI的embedding可以指定降维参数,从常用模型的输出维度直接压一半甚至更多。1536维压到512维,原始数据体积和索引体积同比例缩小,HNSW图构建时的内存开销也跟着下降。
更狠一点的做法是做标量量化(Scalar Quantization)。把每个浮点数从4字节压到1字节,检索时用量化后的近似向量,召回率损失通常控制在2%以内,但内存和存储直接缩水75%。HNSW索引对这类的容忍度很高,尤其在RAG的top-K场景下,2%的召回损失和10%的成本下降相比,我会毫不犹豫选后者。
我的习惯是:先跑一组离线评测,量化前和量化后在标准测试集上各测一次Recall@K指标,如果下降超过3%,再评估是否需要放弃量化;如果下降在可接受范围内,直接对全量数据重新量化入库。这一步能减少的OpenSearch侧费用,经常是本文账单计算里的最大单项。
5.3 HNSW参数和副本数的反向优化
很多人建HNSW索引时使用默认参数,然后怀疑“为什么检索这么慢”。现场经验的答案是:在数据量不大于500万条时,m=16、efConstruction=100、efSearch=200是一套性价比非常高的黄金组合。
重点在副本数。OpenSearch Serverless默认为了达到高可用会保留多副本,每加一个副本,存储和搜索OCU同比例增加。如果只是RAG内部批量跑,不上用户在线查询,把副本数压到0,单写单查,成本直接下降40%。千万记得,这个操作是在OpenSearch Serverless的Collection配置里,不在DynamoDB里。
5.4 用冷热分层给向量数据做瘦身
RAG有一个特点:有些知识库文档是“永远都会被反复检索”的热数据,比如产品手册的核心章节;有些则是“存了但一年没人问”的冷数据,比如历史新闻、过季公告。向量索引不分亲疏,全部一视同仁地占着内存和计算资源。
我给一个大型RAG项目做的方案是:把文档按最近访问时间打上冷热标签,热数据放在向量索引里,冷数据由DynamoDB表存放、配上定期S3归档。查询时先检索热索引,没召回再回退查冷数据的粗索引。整体效果是:存储成本下降了60%,查询延迟几乎无感。因为冷数据的检索频率本身就低,回退带来的少量延迟完全在可接受范围内。
5.5 CloudWatch成本监控的兜底防线
最后一条,所有开了DynamoDB原生向量搜索的团队,都应该在第一天就建立起来——给DynamoDB表和OpenSearch Serverless的Collection打上统一的Cost Allocation Tag,并在CloudWatch里配置OCU利用率的告警。
没有这个兜底,账单涨了你都未必能第一时间发现是哪个环节在漏钱。设置了成本标签后,在Cost Explorer里可以按标签聚合,一眼分清今日花销是DynamoDB侧涨了还是OpenSearch侧涨了。这个习惯能让你在成本刚出现异常趋势时及时干预,而不是等到月底账单出来才傻眼。
我个人的阈值是:Indexing OCU若持续24小时利用率高于80%,就检查数据批次是否过密、是否需要调大索引构建的efConstruction;Search OCU若持续12小时利用率低于30%,就把副本数往下调,别让空闲资源白白烧钱。
6. 真到了要换那天,平滑迁移怎么做
如果你执行了全部成本治理手段之后,发现项目规模已经进入重量级区间,决定切换到独立向量数据库,这时候别急着把DynamoDB一脚踢开。平滑迁移的核心思路是“保留源系统,逐步引流,双写过渡”。
6.1 双写阶段的设计
DynamoDB上已经开了Streams的话,天然就具备CDC能力。利用这个机制,把原本同步到OpenSearch的Lambda目标换一个新实现,同时写入新向量数据库,比如Qdrant或Milvus。新旧向量库同时持续服务,持续一段时间,确保两者数据完全对齐。
要注意的是,新向量库的索引参数要和旧库对齐,否则迁移后召回效果会出现肉眼可见的波动。一个稳妥的做法:迁移前在离线环境下用全量数据构建新库索引,跑一遍和旧库相同的评估集,对比Recall@K和P95延迟,达标了再切换线上流量。
6.2 切流顺序:先灰度再全量
切换线上流量时,先从1%的用户开始灰度,观察延迟和召回反馈,没异常再逐步放大。这里有个容易被忽略的细节:不要把DynamoDB主表的写入逻辑一并改掉。DynamoDB继续作为主存储和事务源,向量库只承担检索职能,这样回滚路径永远存在。
对于RAG场景,召回结果里通常会附带DynamoDB主键,查询到结果后再用BatchGetItem回主表取完整文档内容——这套架构里,DynamoDB依然是RAG链路不可或缺的一环,向量库只是把“找相似”这一步替换成了更强的引擎。
切流结束后,DynamoDB侧的向量索引可以关闭。但主表如果还有审计需求,建议至少保留备份快照,迁出数据后仍然保持低成本存储,应急回滚或复查时随时可用。
6.3 迁移中的一片雷区:删除顺序
有一件事千万不能做错顺序:先关DynamoDB的向量索引,再停Streams,最后切流量,这个顺序没问题,但反过来就很麻烦。
如果你先把写入流量切走,DynamoDB的新增数据不再产生Streams事件,但旧向量库里还有存量数据没有回填完毕,新库的增量持续接入,两边数据就会不不一致。我见过一个团队就是这么踩坑的——切流当天发现新库搜索结果东缺一块西缺一块,排查了一整天才发现是回填任务和切流动作的时序反了。
正确顺序是:先做全量回填→并行双写验证数据一致性→灰度切流量→确认稳定后关闭旧索引→最后整体清理旧向量库资源。每一步验证通过后再走下一步,整个过程虽然多花几天时间,但比晚上被线上告警叫起来强太多了。
7. 我的最终看法:这个“换不换”的问题没有标准答案
兜兜转转了这么多,回到最开始的疑问:DynamoDB原生向量搜索的账单翻倍,到底该不该把它换掉?
我的答案是:不要因为“贵”就换,要看这个“贵”换回了什么。
如果你的RAG项目处于数据量百万以内、团队刚好已经熟练使用DynamoDB、对事务一致性要求高,那么即便每月的OpenSearch OCU费用看着肉疼,它换回的是不需要额外维护一套向量库的省心,以及DynamoDB原生API的便捷。这个账算下来,留在原方案是理性的。
如果你的项目数据量已经突破百万级、查询模式复杂、需要重度混合检索或卡在延迟预算的红线上,那再为了不迁移而硬撑原有的原生向量搜索,就不是省心而是麻痹了。上面给的双写迁移方案,足够让你在不停服的前提下一步步切到更合适的引擎。
最后分享一个我自己的小习惯:每季度做一次成本复盘,把向量数据规模的增速、检索QPS的变化趋势、单次检索的平均成本这三个指标拉出来对比。在做这个复盘之前,我对“到底要不要换存储层”的判断也常常摇摆;有了数据之后,很多摇摆问题其实自己就有了答案。技术选型这件事,最怕的不是贵,是没有一个可以解释清楚贵在哪、值不值的完整账本。希望这篇文章能帮你把这本账记明白。