对于大多数数据库来说, “删除”相比于“新增”都是更痛,代价更高。原因如下:
以上两点,使得delete对于数据库的设计和实现都提出了额外的要求。
对于Milvus这种存算分离的向量数据库,删除操作的痛点比其他数据库更甚:
保持vector index的immutable属性,通过bitset掩码的方式来使得被删除的vector不可见。如下图,在vector index中node=2被delete mask标记为1, 即deleted。那么在vector index traverse的过程中,node2会被跳过,但该节点与其他节点的link仍然被作为检索的edge进行使用。
如上图所示,在milvus中,delete和insert一样,同样要双写存储和计算节点。在DataNode上,delete操作被存储为deltalogs然后upload到object storage上, 在QueryNode上,delete被delegator转发给所有“可能包含对应delete数据”的segment,在对应计算节点上生成对应的delete mask以供查询,从而保证delete的可见性。
在前几篇文章中我们提到,milvus的查询request都是发给delegator再由delegator转发给其所管辖的segment的,之后再由delegator汇总查询结果返回给proxy。那么这里一个很自然的想法是,为什么不把delete mask只存在delegator上,然后在汇总查询结果的时候将deleted rows去除掉呢?这样就能避免广播delete造成的写放大问题,整个流程也会变得简单。
如此的确是能保证查询的正确性,但是却不能保证查询结果符合client需求,因为“汇总再删除”可能导致汇总的结果根本不足topk。如下图所示,client要求top2, 3个segment各自返回自己的top2,但问题是此时的delete mask中,12348都已经被置为1了,那么汇总后就只有pk5这一个结果。相比之下,如果delete mask广播到各个segment上,则不会出现这个问题。
上文所介绍的主要是静态条件下delete问题,而在一个实时更新的系统中。“看到数据被删除”和“何时才能看到被删除”有很大的不同,后者对于delete的时序提出了更高的要求,这个问题我们会在后续的文章中展开讨论。
本文从存算分离的视角出发,审视了milvus这一类架构下delete设计与实现的痛点,并介绍了针对这些痛点milvus采用的对策。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。