Skip to content

原始特征向量存储

qiutianme edited this page Jul 20, 2020 · 2 revisions

介绍

Vearch原始向量存储分为MemoryOnly、Mmap和RockDB三个版本。MemoryOnly版是纯内存版,所有的原始向量都存储在内存中。Mmap版是将原始向量存储在磁盘文件中,然后通过mmap系统调用将文件内容映射到内存地址空间。RocksDB版是基于RocksDB开源数据库,它将所有的原始向量存储到底层RocksDB数据库。

优劣势分析

介质类型 版本 优势 劣势
内存 MemoryOnly 顺序、随机访问性能都高 内存占用高,存储数据量小(单机千万级)
磁盘 Mmap 只占用少量内存缓冲,存储数据量大(单机亿级),不依赖第三方库 随机访问性能低,目前不支持inplace-update
RocksDB 只占用少量内存缓冲,存储数据量大(单机亿级) 随机访问性能低,依赖第三方库

MemoryOnly版

MemoryOnly版是将原始向量存储在连续的内存空间,支持按vector_id随机访问原始向量。

旧版MemoryOnly在初始化时,一次性就分配足够大的连续内存空间,这带来了两个问题:1. 原始向量的最大容量在初始化的时候就已固定(max size),后续无法动态扩展;2. 一般来说,业务的数据量都是缓慢增长的,大部分内存在较长的时期内都无法被利用,浪费内存空间。

新版MemoryOnly采用了分段连续存储的方案,具体方案如下图所示。它主要是对内存空间进行分段处理,每个段存储固定数量的原始向量(比如100万),且段内仍然是一块连续的内存。初始化时,只创建一个段0,当段0被写满之后,再分配段1,依次按需增加段。这样就实现了一个按需分配内存的方案,解决了以上的两个问题。并且新版仍然保留了随机访问原始向量的功能,只是在随机访问之前需要通过vector_id计算segment_id和offset,具体计算方式如下,其中segment_size是每个段的大小。

  1. segment_id = vector_id / segment_size
  2. offset = vector_id % segment_size

memory_only_raw_vector.jpg

Mmap版

Mmap版是vearch自研的磁盘版原始向量存储方案,不依赖任何第三方库或包,开箱即用。它主要解决的业务场景是:内存容量有限,数据量特别大(亿级),对随机访问原始向量的性能不敏感。

Mmap版实现的方案如下图。插入原始向量时,首先将原始向量插入到内存中的高速循环缓冲队列,然后由异步线程批量地将原始向量刷到磁盘文件。这样的目的是利用批量写,减少磁盘io,提高写的性能,从而提高插入原始向量的性能。

系统初始化时,会通过mmap系统调用将磁盘文件映射到(逻辑)内存地址,这样就可以通过该内存地址访问原始向量。备注:mmap并不是将所有的原始向量读取到内存,而是通过不断的加载和换页达到访问超过物理内存大小的文件的,具体可参见mmap的实现。

mmap_raw_vector.jpg

RocksDB版

RocksDB版和Mmap版一样,同样是利用磁盘来解决内存容量有限的问题。不同的是RocksDB版底层利用了第三方库RocksDB来存储原始向量。

初始化时,创建一个RocksDB的数据库db_

插入向量时,将vector_id格式化为字符串类型的rowkey,然后调用RocksDB的put接口,将rowkey和原始向量(value)插入到db_中

读取向量时,同样将vector_id格式化为字符串类型的rowkey,然后调用RocksDB的get接口从db_中获取原始向量

Clone this wiki locally