从Milvus+ES到Lindorm:AI应用数据存储架构的演进与实战
2026/8/10 5:19:13 网站建设 项目流程

1. 项目概述:AI应用数据存储的十字路口

最近和几个做AI应用开发的朋友聊天,发现大家普遍卡在一个问题上:数据怎么存?尤其是当你的应用开始处理非结构化数据,比如图片、音频、长文本,或者需要做复杂的语义搜索、推荐时,传统的关系型数据库就显得力不从心了。这时候,大家通常会想到两个“明星选手”:Milvus和Elasticsearch(ES)。前者是专为向量计算而生的数据库,后者是全文检索领域的霸主。很多团队的选择是,把Milvus和ES“拼接”起来用,Milvus管向量相似度搜索,ES管关键词过滤和元数据管理。这个方案听起来很合理,对吧?但实际干过的人都知道,这里面的坑,一个比一个深。

我自己的团队也走过这条路,直到我们遇到了一个更“省心”的选项——阿里云Lindorm。今天这篇东西,就想聊聊我们为什么最终从“Milvus+ES拼接”的架构,转向了Lindorm这个“一栈式”的解决方案。这不仅仅是选型的变化,更是对AI应用数据层架构设计思路的一次重新审视。如果你正在为你的AI应用(无论是大模型智能体、RAG系统还是推荐引擎)寻找数据底座,或者正在被多系统维护、数据一致性、运维复杂度搞得焦头烂额,那接下来的内容或许能给你一些直接的参考。

2. 核心需求解析:AI应用对数据层的真实诉求

在深入对比方案之前,我们必须先搞清楚,一个典型的AI应用,它的数据层到底在承受什么样的压力。这绝不是简单找个能存数据的地方就行。

2.1 多模态数据与混合查询

现在的AI应用,数据形态非常复杂。以一个大模型知识库应用为例:

  • 向量数据:这是核心。用户的问题、文档的切片,都需要通过Embedding模型转换成高维向量(比如768维、1024维)。应用需要能快速从海量向量中找到最相似的Top-K个结果,这就是向量相似度搜索。
  • 结构化元数据:每一条向量数据都关联着丰富的元信息。比如,它来自哪篇文档(doc_id)、属于哪个章节(chapter)、作者是谁、创建时间、标签(tags)等。用户经常需要组合查询:“帮我找一下关于‘机器学习’的,并且是最近三个月内发布的,作者是张三的文档”。这需要高效的多字段过滤、范围查询和聚合。
  • 全文内容:原始的文本内容本身也需要被检索。虽然向量搜索能理解语义,但精确的关键词匹配、短语查询、模糊查询仍然是刚需。用户可能记得文档里的某个特定术语,需要快速定位。

所以,一个查询往往是“混合”的:先根据关键词或属性过滤出一批候选集,再在这个候选集里做向量精排;或者先做向量粗筛,再用元数据条件进行过滤和排序。这种“向量搜索 + 属性过滤 + 全文检索”的三合一查询,是AI应用的典型模式。

2.2 极致的性能与扩展性要求

AI应用对延迟极其敏感。一个智能客服机器人,如果召回相关知识的耗时超过200毫秒,用户体验就会大打折扣。这意味着:

  • 高并发低延迟:向量检索和属性过滤都必须在毫秒级完成。
  • 海量数据支撑:数据量可能从百万级迅速增长到十亿级,系统需要能近乎线性地扩展,不能因为数据增长而导致性能骤降。
  • 高吞吐写入:数据更新、新的Embedding生成,需要能够实时或近实时地写入并生效,支持流式数据摄入。

2.3 运维与成本的现实考量

对于大多数产品团队而言,工程师资源是宝贵的。维护两套独立的、复杂的数据库系统意味着:

  • 双倍的学习与运维成本:你需要团队里既有懂Milvus调优的人,也有懂ES集群运维的人。
  • 数据同步与一致性的噩梦:如何保证写入Milvus的数据和写入ES的数据是原子性一致的?网络故障导致一个成功一个失败怎么办?这需要引入额外的消息队列和同步程序,复杂度指数级上升。
  • 资源浪费:两套系统通常意味着双倍的硬件或云资源开销,而且可能存在资源利用率不均衡的问题。
  • 故障排查困难:当查询结果不符合预期时,你需要同时在两个系统中排查,难以确定问题是出在向量检索部分、过滤部分,还是数据同步的延迟上。

理解了这些真实且具体的痛点,我们再回过头看“Milvus + ES拼接”的方案,就能更客观地评价它的优劣了。

3. 传统方案深度剖析:Milvus与ES拼接的得与失

“Milvus管向量,ES管过滤和全文”,这个思路直观且在一段时间内是可行的。我们来拆解一下它的实现和背后的代价。

3.1 方案架构与典型工作流

一个典型的拼接架构如下图所示(此处为逻辑描述):

  1. 数据写入端:应用收到一条新文档。
    • 将文档切片,通过Embedding模型生成向量。
    • 将向量和对应的文档ID写入Milvus。
    • 将文档的元数据(ID、标题、标签、时间等)和原始文本内容写入Elasticsearch。
    • 这里需要一个事务或至少是保证最终一致性的机制,确保两边数据关联得上。
  2. 混合查询端(最复杂):用户发起一个查询“找找去年关于神经网络优化的论文”。
    • 路径A(先过滤后向量):先将查询词“神经网络 优化”在ES中进行全文检索,并结合时间范围“去年”进行过滤,得到一批候选文档ID列表。然后将这个ID列表作为过滤条件,连同查询文本生成的向量,提交给Milvus进行向量相似度搜索。Milvus只在这批ID对应的向量中进行查找。
    • 路径B(先向量后过滤):先用查询文本生成向量,在Milvus中进行全量向量相似度搜索,得到Top-N个向量ID及其分数。然后拿着这些ID去ES中查出对应的元数据,再在应用内存中根据元数据进行二次过滤和排序(比如时间范围)。
    • 选择哪条路径,取决于你的数据分布和查询模式,需要大量测试和调优。

3.2 优势:术业有专攻

这个方案最大的优势在于利用了两个领域最顶尖的开源工具。

  • Milvus:在向量检索方面性能卓越,支持多种索引类型(IVF_FLAT, HNSW, SCANN等),针对GPU加速做了优化,社区活跃,是向量数据库的事实标准之一。
  • Elasticsearch:在倒排索引、分词、复杂查询、聚合分析方面功能无比强大,生态成熟,有海量的插件和工具支持。

在项目早期,数据量不大、查询模式简单时,这个组合能快速搭建起来,并且各自都能发挥出不错的性能。

3.3 痛点与挑战:1+1<2的困境

然而,随着应用规模增长,痛点会逐一暴露:

  1. 数据一致性难题:这是最大的架构隐患。除非引入分布式事务(成本极高),否则很难保证Milvus和ES中的数据完全同步。网络抖动、服务重启都可能导致一边写入成功另一边失败。你不得不编写复杂的补偿逻辑(如重试、对账、修复脚本),这增加了系统的不可靠性和维护负担。

    注意:我曾遇到过在流量高峰时,ES写入延迟增大,导致用户查询时,向量已在Milvus中,但元数据还未同步到ES,结果过滤条件失效,返回了错误的数据。排查这种问题极其耗时。

  2. 查询性能瓶颈:混合查询的链路变长了。

    • 如果走“先ES后Milvus”路径,当ES过滤后的ID列表仍然很大(比如数万个),Milvus的检索性能会受到影响,因为它的索引结构可能不是为这种“带条件的大范围检索”优化的。
    • 如果走“先Milvus后ES”路径,Milvus返回的Top-N可能很大(比如1000),然后需要用这1000个ID去ES做“terms query”拉取元数据,这个查询在ES中开销不小,尤其是并发高的时候。而且,如果Top-N的结果在元数据过滤后所剩无几,那么前期的向量搜索就做了大量无用功。
    • 网络往返开销:一次查询需要在应用、Milvus、ES之间进行多次网络通信,延迟累加。
  3. 系统复杂度与运维成本激增

    • 部署与监控:你需要维护两套集群,监控它们的CPU、内存、磁盘、网络指标,以及各自独特的健康状态(如Milvus的数据段、ES的分片状态)。
    • 容量规划:你需要分别预估Milvus和ES的数据增长和资源需求,很难做到平衡,容易造成一个资源紧张另一个资源闲置。
    • 升级与故障:任何一个系统的升级或故障,都可能影响整个查询链路。你需要制定复杂的容灾和降级方案。
  4. 开发体验割裂:开发者需要学习两套API、两套查询语言、两套客户端。编写一个混合查询的业务代码,逻辑分散,难以理解和调试。

4. 一栈式方案:阿里云Lindorm的核心能力解构

当我们被上述问题困扰时,开始寻找“All in One”的解决方案。阿里云Lindorm进入了视野。Lindorm本身是一个面向海量数据设计的云原生多模数据库,它的一大亮点就是原生融合了宽表、时序、搜索、向量等多种数据模型和能力。对于AI应用场景,它的价值在于用一个数据库解决多个问题。

4.1 多模融合引擎:向量、全文、宽表一体

Lindorm的核心在于其“融合引擎”。你不需要再拼接多个系统,而是在一个Lindorm数据库实例内,创建一张表,这张表可以同时拥有:

  • 宽表列:用于存储结构化的元数据,如ID、标题、作者、时间戳、标签等。支持高性能的随机读写和范围查询。
  • 全文索引:对指定的文本列(如内容、摘要)自动构建倒排索引,支持Elasticsearch兼容的Query DSL进行复杂的全文检索、分词和聚合。
  • 向量索引:对指定的向量列(如embedding)自动构建向量索引(支持HNSW、IVF等算法),支持高效的近似最近邻(ANN)搜索。

最关键的是,这些能力是在同一份数据上实现的。你写入一行数据,它同时具备了可被宽表API、搜索API和向量API访问的能力。数据天然一致,无需同步。

4.2 混合查询(Hybrid Search)的原生支持

这是Lindorm对比拼接方案最具杀伤力的特性。它提供了一种统一的查询语法,允许你在一次请求中,同时指定向量相似度条件、属性过滤条件和全文检索条件。查询引擎会智能地将这些条件下推到存储层进行协同计算。

例如,一个查询语句的简化示意可能是这样的:

SELECT id, title, content, l2_distance(embedding, [0.1,0.2,...]) as score FROM my_ai_table WHERE vector_search(embedding, [0.1,0.2,...], 'top_k=100') -- 向量搜索 AND author = '张三' -- 属性过滤 AND text_match(content, '机器学习 优化') -- 全文检索 AND publish_time > '2023-01-01' ORDER BY score ASC LIMIT 10

数据库内部会优化执行计划,可能先利用向量索引快速缩小范围,同时利用倒排索引和列存过滤进行剪枝,最终合并出最相关的结果。这避免了应用层多次网络交互和内存中的二次处理,性能提升显著,延迟更可预测。

4.3 云原生架构带来的运维简化

作为阿里云的产品,Lindorm天然具备云服务的优势:

  • 弹性伸缩:存储和计算分离架构。你可以独立扩展存储容量或计算资源(CU,Capacity Unit),根据业务流量快速弹性扩缩容,按实际使用量付费,成本更优。
  • 高可用与备份:默认多副本、跨可用区部署,数据自动备份与恢复,服务等级协议(SLA)有保障。你不需要自己搭建和维护复杂的集群高可用机制。
  • 托管服务:无需关心底层服务器、操作系统、数据库软件的安装、补丁和升级。控制台提供了完整的监控、告警、慢查询分析工具,运维重心从“保稳定”转移到“调优和业务创新”。

5. 从拼接架构迁移到Lindorm的实操指南

如果你已经被“Milvus+ES”的架构折腾得够呛,下决心迁移,下面是一个可行的实操路径和关键注意事项。

5.1 迁移评估与规划

  1. 数据模型映射
    • 分析现有Milvus中的Collection和ES中的Index。确定哪些字段是元数据(映射到Lindorm的宽表列),哪些字段需要全文检索(创建搜索索引),哪个字段是向量(创建向量索引)。
    • 设计Lindorm的表结构。一个通用的建议是:主键列(如doc_id)、多个属性列(title,author,tags等)、一个文本列(content)、一个向量列(embedding,类型为VECTOR)。
  2. 查询模式分析:梳理现有应用中的所有混合查询,将其转化为Lindorm支持的Hybrid Search查询形式。Lindorm兼容SQL和部分ES Query DSL,迁移工作量相对可控。
  3. 容量与性能预估:根据现有数据量和QPS,在阿里云控制台使用Lindorm的容量计算器,预估需要的存储空间和CU数量。建议初期选择弹性模式,便于调整。

5.2 数据迁移与双写过渡

切忌一次性割接,风险太大。建议采用“双写+流量逐步切换”的策略。

  1. 搭建新链路:在应用代码中,接入Lindorm客户端。在写入原有Milvus和ES的同时,同步写入Lindorm。写入Lindorm时,就是单次写入,无需关心同步问题。
    // 伪代码示例:双写逻辑 public void saveDocument(Document doc, float[] embedding) { // 1. 原有拼接架构写入(异步或事务保证) milvusClient.insert(embedding, doc.getId()); esClient.index(doc.toJson()); // 2. 同步写入Lindorm(一栈式) lindormClient.execute("UPSERT INTO ai_docs (id, title, author, content, embedding) VALUES (?, ?, ?, ?, ?)", doc.getId(), doc.getTitle(), doc.getAuthor(), doc.getContent(), embedding); }
  2. 数据全量迁移:编写迁移脚本,将历史数据从Milvus和ES中导出,并转换为Lindorm的格式后导入。可以利用Lindorm的BulkWrite接口或数据集成工具(如DataX)提高效率。务必做好数据校验,对比记录数、抽样对比查询结果。
  3. 查询流量灰度
    • 第一阶段:让少量只读查询(如内部测试、小比例线上流量)走Lindorm新接口,对比结果和性能,持续优化查询语句和索引。
    • 第二阶段:逐步扩大走Lindorm的查询流量比例,比如10% -> 50% -> 100%。同时严密监控Lindorm的CPU使用率、延迟、错误率。
    • 在整个过程中,旧有的Milvus+ES链路保持在线,作为应急回退方案。

5.3 索引优化与参数调优

数据迁移后,性能调优是关键。Lindorm的向量检索性能与索引参数强相关。

  1. 向量索引类型选择

    • HNSW:适用于高召回率、低维度的场景。构建慢、查询快、内存占用高。efConstructionM参数影响构建质量和速度。
    • IVF:适用于大数据量、对构建速度有要求的场景。需要先进行聚类。nlist参数控制聚类中心数,影响精度和速度的平衡。
    • 建议:对于AI应用常见的百维到千维向量,追求高查询性能,可优先测试HNSW。
  2. 创建索引的SQL示例与参数解读

    CREATE VECTOR INDEX idx_embedding ON ai_docs (embedding) WITH (index_type='HNSW', distance_type='L2', m=16, ef_construction=200);
    • m:HNSW图中每个节点的最大连接数。值越大,图越稠密,精度越高,但内存占用和构建时间也增加。通常设置在16-48之间。
    • ef_construction:构建时动态候选列表的大小。值越大,构建质量越高,速度越慢。
    • distance_type:根据你的Embedding模型选择,L2(欧氏距离)或IP(内积,Cosine相似度常转化为内积)。
  3. 混合查询的编写技巧

    • 善用过滤下推:在WHERE子句中,将选择性强的属性过滤条件(如author='张三')放在前面,可以帮助查询引擎提前过滤大量数据。
    • 控制返回数量vector_search函数中的top_k参数不宜过大,通常100-500即可满足精排需求,避免不必要的计算开销。
    • 理解执行计划:使用EXPLAIN语句分析你的Hybrid Search查询,观察是否有效利用了向量索引和搜索索引。

6. 常见问题与性能优化实战记录

在实际迁移和使用Lindorm的过程中,我们遇到并解决了一些典型问题。

6.1 典型问题排查清单

问题现象可能原因排查步骤与解决方案
向量搜索召回率低1. 索引参数(如m,ef_construction)设置不合理。
2. 向量维度或距离度量方式不匹配。
3. 数据未成功建立索引。
1. 逐步调高mef_construction,在构建时间和召回率间权衡。使用小数据集验证不同参数下的召回率。
2. 确认CREATE INDEX时的distance_type与模型训练时使用的相似度计算方式一致。
3. 执行CHECK INDEX命令确认索引状态为ACTIVE
混合查询延迟高1. 返回的top_k过大。
2. 属性过滤条件选择性差,导致扫描数据量过大。
3. 未同时命中向量和全文索引。
1. 评估业务需求,适当减小top_k值。
2. 为常用的过滤字段创建二级索引(对宽表列)或调整搜索索引的Mapping。
3. 使用EXPLAIN查看查询计划,确保条件被下推。考虑将复杂的全文检索拆分为更精确的关键词组合。
写入速度慢1. 单条写入频繁。
2. 向量索引构建占用资源。
3. CU资源不足。
1. 改用批量写入(Batch Insert)接口,一次性写入多条记录,效率可提升数倍至数十倍。
2. 对于大规模初始导入,可以考虑先导入数据,后创建向量索引。
3. 在控制台监控CU使用率,若持续高于70%,考虑临时或永久扩容。
内存使用率高1. HNSW索引内存占用高。
2. 查询并发过高。
3. 缓存配置不当。
1. 对于超大规模向量数据,可评估使用IVF索引以节省内存,或升级节点规格。
2. 在应用层引入查询队列或限流,控制并发度。
3. 联系Lindorm技术支持,调整JVM或缓存相关参数。

6.2 性能压测与调优心得

在切流前,我们做了严格的压测。这里分享几个关键点:

  1. 压测环境隔离:一定要在独立的测试实例上进行,避免影响线上业务。使用和生产环境同规格甚至更高规格的配置。
  2. 模拟真实流量:压测脚本不要只模拟单一查询。应该从生产日志中采样出不同类型的查询(纯向量、纯关键词、混合查询),并按照真实比例混合,形成压测用例集。
  3. 关注核心指标
    • P99延迟:这比平均延迟更重要。它反映了长尾请求的体验,确保绝大多数用户请求都快。
    • CU利用率:观察在目标QPS下,CU的使用情况。为线上运行预留30%左右的缓冲空间。
    • 错误率:压测过程中任何非200的响应都需要关注,可能是触发了限流或参数配置问题。
  4. 参数调优是一个循环:根据压测结果,调整索引参数(如HNSW的ef_search,它影响查询时的精度和速度)和查询参数(如top_k)。然后再次压测。我们经历了3-4轮调整,才找到最适合我们业务场景的参数组合。

6.3 成本控制建议

使用云服务,成本意识很重要。

  • 选择存储弹性模式:Lindorm的存储按量计费,独立于计算资源。这非常适合数据量持续增长但访问模式可能有波动的AI应用。
  • 计算资源按需弹性:利用Lindorm的弹性CU能力。在业务高峰期(如白天)自动扩容,在低谷期(如深夜)自动缩容。可以设置定时弹性策略或基于监控指标的自动弹性策略。
  • 数据生命周期管理:对于有明确冷热特征的数据(例如,仅最近一年的数据被频繁查询),可以利用Lindorm的多级存储功能,将冷数据自动转存至更低成本的存储介质(如OSS),并在查询时透明访问,大幅降低成本。

从“Milvus+ES拼接”到“Lindorm一栈式”,对我们团队而言,不仅仅是技术组件的更换,更是一次数据架构的现代化升级。它让我们从繁琐的同步逻辑和复杂的运维中解脱出来,将更多的精力投入到业务逻辑和算法效果的优化上。当然,没有银弹,Lindorm作为一款云服务,其锁定性是需要考虑的。但对于追求快速迭代、稳定可靠和运维效率的AI应用团队来说,它所提供的“开箱即用、一体融合”的能力,无疑是一个极具吸引力的选择。如果你的应用正处在数据量快速增长、查询复杂度提升的十字路口,不妨花点时间评估一下这个一栈式的可能性。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询