前言
存算分离是一个很火的话题,基本上各个数据库都说自己已经实现,或者即将上线存算分离的架构。但事实上对于不同类型的数据系统,如何定义“存”和“算”是不同的。本系列会简介milvus的存算分离架构,结合具体问题场景聊一些作者对这个概念的看法。
Milvus 存算分离整体架构
由于向量查询的“重索引”“重计算”特型, milvus的存算分离有两层含义:
生成存储文件和查询计算的进程分离
如下图,整个milvus的读写流程是:
- proxy将msg写入message queue中(一般为kafka,pulsar,rocksmq)
- Datanode节点从message queue中消费msg,
- 生成对应的数据分片:segment,并上传到object storage上。
- mixCoord也就是协调节点收集生成的segment
- mixCoord指挥QueryNode节点加载对应的segment以供查询
所以从这个流程上看,生成存储文件的过程发生在DataNode上,而使用存储数据进行查询计算则发生在QueryNode上。两个过程互不干扰,可以分别进行弹性扩展。在查询计算密集的时段,可以扩展QueryNode的数量&&资源,在写入压力较大的时候,可以扩展DataNode节点&&资源
文件存储的位置和使用的位置分离
另一个层面的存算分离,则是数据存储位置(obect storage)和计算发生位置(QueryNode)的分离。milvus的segment是immutable的,所以天然地支持‘一写多读’。
那么Milvus是怎么对表格进行查询的呢?
Milvus分布式查询架构&&前置概念
首先明确几个概念:
- Proxy:milvus查询代理,负责和client直接交互
- QueryNode: milvus的worker node,查询真正发生的进程
- QueryCoord: 查询协调节点,负责管理所有的QueryNode
- Collection: Milvus集合,简单地可以裂解为数据库表
- Segment: Milvus的Query Unit, 可以理解为Milvus的数据分片(类似kudu tablet, es-shard)
- Delegator: 查询首领,负责汇总其所统领的Segment的查询结果
如上图中,可以认为单个Milvus collection有Segment1-5, 5个segment,分别分布在3个QueryNode节点上,其中Delegator分布在QueryNode2上,查询发生的流程如下:
- proxy向QueryCoord询问Milvus Delegator分布,得知该collection的delegator在querynode2上
- proxy向querynode2发送query request
- delegator收到request,将其转发给QueryNode1和QueryNode3上,获取所有segment得查询结果
- delegator汇总所有查询结果,返回给proxy
总结
本文从存算分离的角度,介绍了milvus的分布式架构。