VikingDB:大规模云原生向量数据库的前沿实践与应用

技术

点击上方👆蓝字关注我们!

picture.image

作者|谢剑桥,火山引擎向量数据库高级工程师

VikingDB 简介

picture.image

VikingDB 在字节内部的应用

向量数据库近来的火热来源于大语言模型的兴起,但在大模型兴起之前,VikingDB 已经在字节内部广泛应用,最初应用在推荐、广告、搜索的召回环节,后来逐步扩展到了消重、风控、对话、文档搜索等需要向量检索的其他场景。

在内部推广应用的过程中,VikingDB 经历了非常多样的挑战:超大规模的数据、极致的延迟/性能要求、海量业务场景的接入支持等。为了克服这些困难,我们做了很多架构和性能的优化,以及产品特性的完善。比如:

  • 架构层面:从存算一体、在离线一体逐步演进为了存算分离、在离线分离;为了支持大量业务的低成本接入,VikingDB 支持了平台化、无服务化、数据生态的融合等;
  • 性能层面:为了极致的延迟和成本,支持了 Int4/Int8/fix16 等多种量化方式、基于指令集的计算优化、GPU 加速等;
  • 产品特性层面:除了基础的 ANN 检索功能外,支持了Hybrid (Dense&Sparse) 检索、磁盘索引(DiskANN)、基于向量的粗排打散等。

在内部产品的不断迭代过程中,VikingDB 也逐渐契合云原生的理念,为孵化商业化向量数据库产品打下了坚实的基础。依托于 VikingDB 在字节内部积累的丰富经验,我们在火山引擎推出了 VikingDB 的商业化版本,以更好地对外部客户进行赋能。

应用:Retrieval-Augmented Generation

大语言模型在生成文本方面表现出色,但也存在一些限制,如知识局限性和幻觉问题。为了克服这些挑战,RAG(Retrival-Augmented Generation) 成为了当前业界最流行的解决方案。RAG 结合检索和生成两个关键组件,通过检索为大模型提供相关数据作为上下文信息。由于向量数据库能够高效存储和检索模型生成的向量,从而提供语义上更具有相关性的检索结果,因此向量数据库成了 ES 之外的 RAG 必不可少的检索工具,RAG 也成为了向量数据库最为重要的应用场景。简而言之, 向量库数据库对大模型的价值就是能够提供更准确的语义相关的数据作为上下文信息

picture.image

AI 原生能力

向量(embedding) 是 AI 模型表达非结构化数据的形式, 而向量数据库又是以 embedding 作为核心概念,并围绕其提供存储检索能力的基础软件,因此可以说 向量数据库是 AI 原生应用程序的基础设施

为了更好地胜任 AI 基础设施的角色和贴合大模型的生态,VikingDB 集成了常用的 embedding 模型,用户可以方便地导入、检索文本等非结构化数据,之后 VikingDB 再自动将其转换为向量并存储,最终提供检索能力。

除了近似向量检索,VikingDB 还提供聚类查询、基于向量的相关性排序和多样性打散等能力,以更好地满足 AI 原生应用程序多样的向量计算需求。

另外,除了以向量为核心的基础能力之外,VIkingDB 从模型迭代,信息安全等角度或场景做了特性支持,以更好的产品形态或功能来服务 AI 原生应用程序的研发。

大规模云原生架构

picture.image

VikingDB 基于大规模云原生架构设计,在基础设施层面做了大量开发工作,以降低用户的使用、运维成本:

  • 弹性调度:单租户支持千级别数量的索引,单库百亿候选,用户在使用中无需关心扩容,VikingDB 会自动跟随数据量和请求规模弹性扩缩容,且不同租户之间具有可靠的隔离机制,从而为用户提供了稳定的毫秒级检索能力。
  • 索引管理:支持自动调参,用户无需关注索引参数即可获得最佳的索引性能;支持自动分片,完全免除用户的运维负担。
  • 企业支持:对于企业客户,VikingDB 支持团队协作和权限控制,并提供监控报警能力,有力支持了企业级应用服务的向量检索需求。

基于上述能力,VIkingDB 做到了完全的开箱即用,使用户无需关注运维、资源的扩缩;支持按实际使用量收费,避免闲置浪费,从而降低用户的维护和资源成本。

VikingDB 在极端性能、规模、精度问题的实践经验

极致计算性能

向量检索的性能一般包含两个维度:延时和精度。延时即在线服务的延时;精度即是检索的准确度。向量检索中通常使用的 ANN 索引是一种近似检索,无法保证检索到的结果一定是确定性的、和查询最相关的 topk 条数据,因此 检索精度是向量检索性能的一个重要评估指标 。延时和精度一般是一对互斥的指标,二者无法兼得。

picture.image

上面几张图从索引算法、量化方式、索引参数以及硬件等维度表示了精度和延迟之间的取舍。

最左侧第一张图相对比较了 FLAT、IVF、HNSW 这三种索引算法的计算精度和延迟。向量检索的计算和访存 IO 都非常重,为了提高查询效率,ANN 索引都会对数据做剪枝,不同的索引算法即代表了不同的剪枝策略和不同的剪枝程度。

  • FLAT :暴力索引,不做剪枝,遍历所有数据进行对比。不考虑量化损失的话,精度为 100%,但检索耗时会随着数据量线性增长,因此在数据规模比较大的场景,延迟会严重劣化。
  • IVF :预先对全量数据进行聚类,检索时会遍历最相关的聚类簇。剪枝程度中等,精度和延迟也相对处于中间水准。
  • HNSW :多层图索引,检索过程是一个深度遍历的收敛过程。剪枝程度最高,延迟相对最低,但牺牲了部分精度(根据字节内部经验,一般也在 95% 以上)。

第二张图为量化方式的对比。量化本质上也是一种压缩,压缩就会带来精度的损失。压缩最彻底的是 Int8,对应的精度也最差,VikingDB 能做到 精度损失在 3% 以内

第三张图中所示使用 GPU 加速的情况是个特例,由于硬件上的巨大优势,GPU 在精度和延迟上相比较 CPU 都会有很大提升。但是 GPU 由于显存有限,对大规模数据的支持就比较吃力,GPU 索引加速主要应用于同时对精度和延时都有极端需求,数据量又没那么大的场景。

第四张图:SEF、M 是 HNSW 索引的两个参数,SEF 是搜索时 entry points 的长度,M 是索引图中每个点的邻居节点个数。这两个参数值越大搜索精度越高,但延迟也会越大。

从这几个图也能看出,和检索精度、延迟相关的因素比较多,包括索引算法、量化、索引参数等,这对业务应用的 ANN 选型就造成了一定的使用门槛。索引算法与量化可选项都是有限的枚举值,还比较容易选择,但索引参数的取值就难以确定,不合适的取值很容易造成精度不足或者计算资源的浪费。为此,VikingDB 提供了一些解决方案:

  • 多种索引选型和自动搜参:提供包括 HNSW、IVF、FLAT 在内的多种索引,以及 Int16/Int8/PQ 4bit 等量化方案,然后通过对请求向量分布的实时采集,离线计算搜索最佳索引选型和超参;通过对请求向量实时采样,离线计算搜索最佳的索引选型和参数,并提供检索精度的事实指标。
  • 在线检索精度监控:默认开启自研无损优化,并提供索引的检索精度实时指标。
  • 自研基于 GPU 的 IVF、FLAT 索引加速方案,支持混合计算。

带宽瓶颈下的极致吞吐

在一些超大吞吐的向量检索中,我们发现硬件的瓶颈主要在于内存带宽,因此我们整理出了基于内存带宽的性能预估方法。我们考虑 1000 万条 128 维 Float 向量的 ANN 计算场景,仅就一般情况粗略估算,实际中向量的分布情况会对检索性能和精度产生影响,需要通过搜参调优。

picture.image

以表中第一行举例:对于全精度(Float)的 HNSW 索引,单次检索一般需要访问 1.6W 条数据,那么一次检索的访存量即为 1.6W 条向量数据 * 向量维度 * 4(Float长度)= 8MB,再加上 1MB 的索引结构(HNSW 的每一个向量会和部分向量建立连接,大概需要 1MB 来存储近邻关系),即一次访存需要 9MB。在单实例带宽 30GB/s 时,单实例极限吞吐 QPS 即为 3333。

高效的过滤检索

前面所讨论的是纯 ANN 索引的性能问题,但在实际业务场景中,向量检索经常需要带上标量过滤条件,标量过滤也会对检索性能造成相当大的影响。对于未经优化的 ANN 索引,低过滤比例影响不大,但 ANN 搜索过程与高过滤比例的场景不兼容,高过滤量会破坏 ANN 搜索过程的连贯性,造成精度下降和性能损耗。为此,VikingDB 为不同过滤比例的场景设计了不同的过滤流程,并提前预估过滤比例,来自适应地调整执行计划,以达到最佳的检索性能,加上对某些特殊场景的功能支持,VikingDB 实现了如下所列的技术优势:

  • 对 HNSW,IVF,Flat 索引提供与索引特点匹配的过滤计算流程,支持搜索前、搜索中、搜索后过滤。
  • 针对关键维度自研 TagTree 混合索引,适用于多品类筛选检索场景。
  • 自适应执行计划,预估过滤比例实现最优执行路径,支持检索调试信息返回。
  • 自研 UDF 过滤函数注入机制,实现图灵完备的过滤计算。

极端规模场景

除了在线检索相关的性能问题外,离线建库中会有一些极端场景,诸如亿级数据天级建库、10k QPS 突发写入等超大规模的数据量和超大吞吐的数据导入。在此类极端场景中,向量数据库面临如下挑战:

  • 需要支持各类复杂的数据入库场景,数据写入和存储的模式不是单一的,如何保证各类数据入库场景下的吞吐?
  • 多租户场景下,单一用户的写入如何避免其他租户收到影响?如何做好负载隔离?

实践中,VikingDB 把数据导入模式梳理成了 3 类,并分别做了架构优化,以应对不同的需求场景:

  • 静态库 :数据集固定,后续不再写入或更新。
  • 批式库 :周期性的全量更新,比如模型版本迭代后,需要更新所有向量;也有些场景中,不需要更新所有向量,仅不断地追加。批式库通过 hdfs 等低成本的存储,支持了超大规模的数据导入。
  • 流式库 :数据持续性的单条或小批量写入,有更新、TTL 等需求。极端场景下,有大批量的突发写入,会对数据系统造成稳定性相关的影响。特别是在导入非结构化数据这类场景,有计算 embeeding 这类高耗时的操作。为了避免单一用户的突发写入占用过多资源影响其他用户,VikingDB 引入了quota 和异步多队列机制来保证租户间的隔离,相关计算服务也会根据在线离线等分级做物理隔离。

picture.image

在超大数据规模场景中,除了数据导入和存储外,索引的构建与更新也将成为一个不得不关注的问题。假如需要支持 100 亿 128 维向量,要求 10k QPS 的实时增删、50ms 的延迟,我们可以对这个场景做下展开讨论。

首先,100 亿、128 维的数据大约占用 5T 存储,单机无法构建和服务整个索引,因此需要支持索引的分片,通过控制单分片的向量条数,来约束构建耗时和内存开销。在线服务为了加载并 serving 多分片索引,需要引入一定的状态编排调度机制。

对于实时性需求,单靠全量索引构建无法满足,为此 VikingDB 支持了索引的流式更新机制,用户写入数据会同时触发索引的数据增删。但长时间索引内的增删,会造成 ANN 索引的老化。为此 VikingDB 会根据索引流式更新的数据量比例,来触发全量构建更新,并双 buffer 切换线上索引以保证检索精度和稳定性。

在多分片索引的场景,检索延迟是和分片数相关的。多分片的检索,需要先检索每个分片,然后把每个分片的结果合并在一起,只要有一个分片耗时较长,就会拖累整个索引的延迟。因此从延迟的角度,分片数在满足约束的前提下,应越小越好。为此,VikingDB 提供了自动分片的机制,通过综合考虑各种约束条件计算出最佳分片数。

文本相关性搜索的新范式

关于精度,从业务的角度来说,真正关注的是文本信息的相关性,单纯 ANN 索引的检索精度是 embedding 之间的相关性,如果 embeeding 本身表达能力不足,文本信息检索的相关性会打折扣。相较于传统的关键词检索,向量检索在捕捉语义方面具有优势,但对关键词并不敏感。

对此,业界常规方案是分多路召回然后合并排序,比如一路 ES 做关键词召回,再加一路向量召回。这样能解决前述问题,但会导致系统复杂度的增加和成本的上升,而且在某些场景中并没有完全解决相关性的问题:比如有些数据单从关键词或向量评估,相关性都较低,两路召回均无法检索到;但把关键词和向量叠加起来综合评估,相关性又比较高,这种场景下就导致了召回的不足。

为了解决多路召回的这些问题,VikingDB 引入了混合检索的计算范式,用稠密向量来表征语义,稀疏向量表征关键词,检索时同时将两种向量综合计入相关性分值,这样既提升了结果的相关性,也降低了业务系统的复杂度。

picture.image

如何用好 VikingDB?

前面已经介绍了 VikingDB 在云原生、性能等方面的特色优势以及在字节内部的相关实践经验,目前我们已经把 VikingDB 在向量检索领域积累的技术优势在火山引擎上输出为了商业化产品,以对外部的用户业务进行赋能,这里再简单介绍下 VikingDB 商业化产品的使用。首先介绍下 VikingDB 的两个经典应用案例:图片素材库和企业内知识库。

图片素材库

图片素材库希望给用户提供以图搜图或以文搜图的能力,素材来源于抓取或用户上传,一般图片素材库的数据可达上亿规模。我们可以通过图文向量化模型将图片转换为向量,存储在向量数据库中,向量索引类型在这个数据规模下选用 HNSW 比较合适。有些图片还带有来源、作者 ID、尺寸、类型等辅助字段,因此除了 ID 和 Vector 列,可以添加 source(string),format(string),height(int),width(int),copyright(string) 等标量字段列,将辅助字段作为标量字段存储在向量数据库,后续使用标量过滤即可方便检索。

索引配置方面,为了节约成本,可以开启 Int8 量化, 以 3% 的精度损失换取 80% 的成本收益 ,非常具有性价比。另外,开启索引自动分片,VikingDB 会随着数据规模对资源自动伸缩,完全免除用户的运维负担。

企业内知识库

企业知识库当前也是比较火的场景。假设一家律所内部知识库有多个文档类别,包括法规资料、判例卷宗、内部资料,数据规模有数万至千万级,部分内部资料只有授权人可查,查询需要毫秒级返回多个类别的文献片段以作为大模型问答生成的上下文数据。在大模型时代,VikingDB 就可以作为这些信息的存储工具。由于法律文献具有较多术语,客户希望能通过语义和关键词混合检索,因此我们建议采用 VikingDB 稠密&稀疏向量混合模型作为向量化方法从文档中提取出稠密和稀疏两种向量并存储到 VikingDB。在辅助字段上,需要对文档包含的元信息进行过滤,例如文档类别、是否公开资料、文档产生时间、最近更新时间,因此除了 DocID 和文档原文列,还可以添加 doc_type,is_public,create_ts,update_ts 等标量列。

索引选型上采用 HNSW-Hybrid 索引以支持稠密&稀疏向量混合检索,开启 Int8 量化以节约成本,开启标量索引以支持标量过滤,以 doc_type 字段隔离子索引提高检索精度,多个子索引并发请求,其余过滤条件则在请求时传入过滤表达式。由于数据规模较小,不必进行索引分片。

真实业务场景的避坑指南

以上是 VikingDB 的两个使用 Demo,实践中我们也总结了一些 VikingDB 在真实场景中的避坑指南。

  1. 过滤场景如何选型?分表、子索引、过滤表达式
  • 分表方案 :当向量化方法、授权策略、索引模式、内容类型等存在明显差异时,采用分表方案。
  • 子索引方案 :支持以一个标量列切分子索引,例如为不同的 doc_type 分别构建 HNSW-Hybrid 索引,因此用于关键维度、枚举值不要大于 1000。
  • 过滤表达式(DSL)方案 :最为灵活,支持复杂过滤条件,但相对于前两种方案存在一定的性能损失。
  1. 避免大量重复数据带来的检索问题
  • 预处理去重方案 :如果我们的数据集是批式导入的,显然可以提前按内容去重后写入向量数据库。
  • 相似去重方案 :如果我们的数据是流式写入的,借助于向量库的近似检索能力,可以在写入一条数据前进行一次相似查询,当相似分数接近于 1 时(适用于 cosine 距离),可以避免重复写入。
  • ID 去重方案 :一些情况下,我们可以通过对内容本身进行 md5 并以此为 ID,将内容的真实 ID 放入标量字段在召回时传回。
  1. 知识库中的过期数据淘汰
  • TTL 过期 :借助于 VikingDB 向量数据库的数据 TTL,可以控制数据生命周期,实现自然淘汰。
  • 标注淘汰 :对于知识库中被人工判定失效的数据,应通过业务反馈环路,调用 API 进行数据删除,避免过期的知识造成业务困惑。

VikingDB 接入流程

picture.image

在火山引擎官网( https://console.volcengine.com/auth/login?redirectURI=%2Fml-platform%2Fvikingdb )下单后,即可按照上图的使用流程使用 VikingDB 的向量检索能力:

  • 创建数据集
  • 写入数据,创建索引。没有前后依赖关系,也可以先创建索引再写入数据
  • 最后即可进行向量检索

这些步骤都可以在页面上操作,也可以通过调用API 或 SDK 进行操作,SDK 目前已经支持 Python、Go 和 Java 三种语言。除了基础的向量检索能力,VikingDB 还集成了 embedding 计算、文本等非结构化数据检索、监控告警等产品能力,以满足不同用户的业务场景,为用户提供完整的产品体验。

VikingDB 详细的使用说明可以参照官方文档: https://www.volcengine.com/docs/6459/1163945

点击【 阅读原文 】下载本文对应的 PPT 资料

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论