存储操作
数据插入
客户端通过调用 insert
接口来插入数据,单次插入的数据量不能大于 256 MB。插入数据的流程如下:
- 服务端接收到插入请求后,将数据写入预写日志(WAL)。
- 当预写日志成功记录后,返回插入操作。
- 将数据写入可写缓冲区(mutable buffer)。
insert_buffer_size
决定,默认是 1 GB。
数据落盘
缓冲区中的数据落盘有三种触发机制:
定时触发
系统会定时触发落盘任务。定时间隔由系统参数 auto_flush_interval
决定,默认是 1 秒。
落盘操作的流程如下:
- 系统开辟一块新的可写缓冲区,用于容纳后续插入的数据。
- 系统将之前的可写缓冲区设为只读(immutable buffer)。
- 系统把只读缓冲区的数据写入磁盘,并将新数据段的描述信息写入元数据后端服务。
完成以上流程后,系统就成功创建了一个数据段(segment)。
客户端触发
由客户端调用 flush
接口触发落盘。
缓冲区达到上限触发
累积数据达到可写缓冲区的上限(128MB)会触发落盘操作。
每个数据段的所有相关文件都被存放在以段 ID 命名的文件夹中,比如记录实体 ID 的 UID 文件、用于标记已被删除实体的 delete_docs 文件,以及用于快速查找实体的布隆过滤器(bloom-filter)文件。
数据合并
小数据段过多会导致查询性能低下。为了避免此问题,Milvus 会在需要的时候触发后台段合并任务,即把小数据段合并成新的数据段,并删除小数据段、更新元数据。其中,新数据段的大小不低于 index_file_size
。
合并操作的触发时机如下:
- 启动服务时
- 完成落盘任务后
- 建索引前
- 删除索引后
建立索引
未建立索引之前,Milvus 对集合的查询操作都是以暴力搜索(brute-force search)的方式完成的。为提高查询性能,你可以为集合建立合适的索引。索引建成后,每个数据段都会产生一个索引文件,此时元数据也会同步更新。
删除
删除集合
- 客户端调用
drop_collection
接口来删除一个集合。 - 服务端接收到请求后,仅在元数据中把该集合(包括它的分区和段)标记为删除状态。对于已标记为删除状态的集合,将无法再对其进行任何新操作(比如插入和查询)。
- 后台的清理任务将被标记为删除状态的集合(包括它的分区和段)从元数据中删除,然后将该集合的数据文件和文件夹从磁盘上删除。如果在删除操作之前已经有对该集合的操作正在执行,后台清理任务不会删除正在使用的段,直到操作完成。
删除分区
- 客户端调用
drop_partition
接口来删除一个分区。 - 服务端接收到请求后,仅在元数据中把该分区(包括它的段)标记为删除状态。
- 后台清理任务按照删除集合的流程来删除该分区和元数据。
删除实体
Milvus 为每个数据段建立了一个 delete_docs 文件,用来记录被删除向量在段内的位置。
Milvus 使用布隆过滤器(bloom filter)来快速判断一个实体 ID 是否可能存在于某个数据段中。因此,在每个数据段下都创建了一个名为 bloom_filter 的文件。
删除实体的流程如下:
- 客户端调用
delete_entity_by_id
接口删除集合中的实体。 - 服务端接收到请求后,执行以下操作删除实体:
- 如果该实体在插入缓冲区中,直接删除该实体。
- 否则,根据每个数据段的布隆过滤器判断该实体所处的数据段,然后更新该数据段的 delete_docs 以及 bloom_filter 文件。
数据段整理
查询一个数据段时,Milvus 会将该数据段的实体数据以及 delete_docs 文件读入内存。虽然被删除的实体不参与计算,但它们也会被读入内存。所以,一个数据段中被删除的实体越多,浪费的内存资源和磁盘空间越多。为了减少此类不必要的资源消耗,Milvus 提供了数据段整理(compact)的操作,流程如下:
- 客户端调用
compact
接口。 - 服务端接收到请求后,根据 delete_docs 所记录的信息,将段内未被删除的实体写入一个新的数据段,并把旧数据段标记为删除状态。之后将由后台清理任务负责清理被标记为删除状态的数据段。如果旧数据段已建立索引,新数据段产生之后会重建索引。
compact
操作会忽略被删除向量占比小于 10% 的数据段。
数据读取
- 客户端调用
get_entity_by_id
接口读取原始实体数据。 - 服务端接收到请求后,通过布隆过滤器找到实体所在的段,返回该实体 ID 对应的数据。
常见问题
Milvus 可以通过扩展某些接口(如 S3 接口、GlusterFS 接口)来扩展存储吗?
目前暂不支持。Milvus 有没有数据导出的功能?
目前没有专门的工具实现该功能。你可以通过get_entity_by_id
得到指定 ID 对应的向量。