前言
年前看了些Milvus QueryCoordV2的代码整理了一些笔记(算是半成品),省去了很多细节。一直为做最终的整理, 直到准备去社区做分享才开始临时抱佛脚翻笔记, 之前看的东西也快忘了。本着输出倒逼输入的原则,还是把他发出来提供给大家指正。最少也是给大家提供个索引
以下是内容目录
- 从一个Load Collection 大概的流程串起来
- 分别看下这几个组件的实现
- 元数据
- Checker
- TaskScheduler & disHandler
- Observer
- NodeUp/NodeDown
LoadCollection流程
概括
QueryCoordV2负责将Segment,Channel分配到QueryNode,更新QueryNode中的LeaderView信息。相较QueryCoordV1,QueryCoordV2在分配数据过程都是异步的操作。在分配的逻辑上也会每个QueryNode粒度分别去分配。
元数据组件
1.Meta
在ETCD中维护集合和副本的信息,包含了两个Manager
-
CollectionManager
:维护集群的集合和分区基础信息和Load进度type CollectionManager struct { rwmutex sync.RWMutex collections map[UniqueID]*Collection partitions map[UniqueID]*Partition store Store } type Collection struct { *querypb.CollectionLoadInfo LoadPercentage int32 //Load进度 CreatedAt time.Time UpdatedAt time.Time }
-
ReplicaManager
:维护副本和分配给这个副本的QueryNode节点IDtype ReplicaManager struct { rwmutex sync.RWMutex idAllocator func() (int64, error) replicas map[UniqueID]*Replica store Store } type Replica struct { ID int64 CollectionID int64 Nodes []int64 //分配给这个副本的QueryNode节点ID }
2.DistributionManager
在内存中维护Segment/Channel/LeaderView在QueryNode实际的分配快照。包含了三个Manager
-
SegmentDisManager
: 记录Segment
的分配情况type SegmentDistManager struct { rwmutex sync.RWMutex // nodeID -> []*Segment segments map[UniqueID][]*Segment } type Segment struct { *datapb.SegmentInfo Node int64 // Node the segment is in Version int64 // Version is the timestamp of loading segment }
-
ChannelDistManager
:记录Channel
分配的情况type ChannelDistManager struct { rwmutex sync.RWMutex // NodeID -> Channels channels map[UniqueID][]*DmChannel } type DmChannel struct { *datapb.VchannelInfo Node int64 Version int64 }
-
LeaderViewManager
: 记录每个节点Leader
与Segment/Channel的之间的关系type LeaderViewManager struct { rwmutex sync.RWMutex views map[int64]channelViews // 节点ID -> Views (one per shard) } type channelViews map[string]*LeaderView //channel -> View type LeaderView struct { ID int64 CollectionID int64 Channel string Segments map[int64]*querypb.SegmentDist GrowingSegments typeutil.UniqueSet }
3.TargetManager
记录需要分配给QueryNode的Segment/Channel
type TargetManager struct {
rwmutex sync.RWMutex
segments map[int64]*datapb.SegmentInfo
dmChannels map[string]*DmChannel
}
后面handoff/load等在QueryNode的操作,会修改TargetManager。通过TargetManager和DistManager,Checker会比对每个replica的差异情况,生成LoadTask/ReduceTask。接下来我们看下Checker的逻辑
Checker
刚才我们提到Checker比对TargetManager和DistManager之间的差异,生成LoadTask/ReduceTask的逻辑。简单说下
实现入口
CheckerController会有个协程定时去check,生成Task加入到TaskScheduler,现在已有的Checker :
- SegmentChecker: 生成Segment相关的Task
- ChannelChecker: 生成Channel相关的Task
- RebalanceChecker: 根据Rebalance策略,生成Loaded Collection的Segment/Channel Task
// check is the real implementation of Check
func (controller *CheckerController) check(ctx context.Context) {
tasks := make([]task.Task, 0)
for _, checker := range controller.checkers {
tasks = append(tasks, checker.Check(ctx)...)
}
for _, task := range tasks {
err := controller.scheduler.Add(task)
if err != nil {
task.Cancel()
continue
}
}