Milvus 数据管理系列(二):数据文件清理机制的改进

作者:莫毅华

日期:2019-12-18

原来的删除策略和相关问题

《Milvus 数据管理系列(一):数据管理策略》一文里我们提到数据文件的删除机制,删除操作有软删除(soft-delete)和硬删除(hard-delete)。执行了删除表的操作后,该表会被标记为 soft-delete 状态,之后对该表的检索或修改操作都是不允许的。但删除之前所执行的查询操作仍在进行,只有当所有对该表的查询操作完成之后,该表才会被真正地删除,包括它的元数据信息和各种文件。

那被软删的文件什么时候才能被真正删除呢,在v0.6.0之前的版本中,采取的策略是当一个文件被软删除5分钟之后才会被真正地删除。下面用一张图来表示这个策略(好吧,我承认这张图治好了我多年的颈椎病):

5mins

这个做法是基于通常条件下的查询不会持续到5分钟这么一个前提,但这并不是一个稳妥的方式,假设极端情况下某个查询请求从开始到结束超过这个时间差,那么该次查询就会失败。为什么失败呢?因为查询开始时先会收集“在当前时间点上可以被查询的文件信息”,然后建立查询任务,接着查询调度器会一个一个地加载文件到内存,然后一个一个地搜索,如果在加载某个文件时发现该文件已经不在磁盘上了,就会查询失败。

而如果把这个时间差设得长一些,确实可以降低查询失败的风险,但是会带来另一个问题:磁盘占用量过大。这个问题发生的原因是,当外部持续大批量地输入向量时,Milvus 内部会不断地合并数据文件,而合并完成的文件并不会立即从磁盘上删除(即使没有查询发生),于是会造成大量处于软删除状态的文件存留在磁盘里。如果插入的数据过多过快,有可能会造成几 GB 甚至几十 GB 的额外磁盘占用。请看下图:

result

如上图所示,第一批插入的数据(insert1)落盘形成文件 file1,接着 insert2 落盘形成文件 file2,后台负责合并文件的线程合并这两个文件成为 file3。然后,把 file1 和 file2 标记为软删除状态。接着第三批插入的数据(insert3)落盘形成文件 file4,后台线程把它和 file3 合并为 file5,然后把 file3 和file_4 标记为软删除状态。

同理,第四批数据(insert6)和 insert5 合并完成,在 t3 这个时间点上,file5 和 file6 被标记为软删除状态,此时,在 t3 和 t4 时间点之间,虽然有多个文件已经标记为软删除状态,但它们全都存留在磁盘上没有被真正删除。只有到了 t4 之后,才会陆续有文件被真正删除。因此,在 t3 与 t4 之间,我们可以计算一下磁盘占用量:64+64+128+64+196+64+256=836 MB,而实际插入的数据量则是:64+64+64+64=256 MB,膨胀了3.26倍!磁盘的写入速度越高,单位时间内的磁盘占用膨胀率就会越高。

v0.6.0 删除策略的改进

因此我们在v0.6.0版本中改变了文件删除的策略,文件的硬删除不再以时间作为触发条件,而是以文件不再被任何任务使用作为触发条件。请看下图:

newstrategy

假设两批向量数据被插入之后,在t1时间点上有一个查询请求进来,这时系统得到两个需要被查询的文件(file1 和 file2,因为 file3 还不存在)。紧接着后台线程开始合并这两个文件,而查询也在同时进行,合并完成得到 file3,将 file1 和 file2 标记为软删除状态。当查询结束后,再没有任何任务会使用 file1 和 file2,于是立刻在 t4 时间点上将它们硬删除。t2 和 t4 两个时间点间隔很短,基本上取决于该查询的时间长短。这样就避免了过多的文件残留在磁盘上,不再使用的文件会被及时清理。

在内部实现上,判断文件是否可以硬删除是通过给文件加引用计数的方式来完成的。引用计数的概念,软件工程师应该都能秒懂。可以通过一个类比了解它的大概意思:玩街机游戏时,当游戏猪脚还有“命”的时候,就能继续玩,当“命”变成 0,就 game over了。具体实现时,Milvus 会监视每个文件的使用状态,当有任务正在使用某个文件时,就会给这个文件加一条‘命’,使用结束后就会给文件减一条‘命’。如果某个文件处于‘软删除’状态,并且它的‘命’已经归零,那么就可以直接把它硬删除。

相关博客

© 2019 - 2020 Milvus. All rights reserved.