scheduler添加任务流程
用户调用Submit函数(如果是自动伸缩的模式,Submit函数将不会被调用,在AutoScaleFrameWork的Init函数中会自己创建一个Task,插入m_wait_queue中而不用TaskProcessor调度),该函数将构建Task结构,并同时插入Task buffer(仅仅是为RPC而写的接口缓冲而使用的),和Task Pool,由TaskProcessor从TaskBuffer中线程取出,调用PlugTask(注意,如果是AutoScaleFramework,则PlugTask会调用SetInfo,设置Task的相关资源,因为AddExecutor时候只提供了Framework ID,没有其他的信息)加入到相应VC中的wait队列。最后由SchedulerProcessor线程周期性从VCPool取出取出Task进行调用AssignTask,该函数匹配运行的的节点资源,然后调用cellet的StartTask函数接口。
若操作成功,TaskProcessor然后带调用TaskAssigned改变Task的状态为运行,但是此时Task还没有被加入framework的运行队列。这个是为什么? 加入运行队列是在cellet调用TaskStart函数之后加入的。(是不是加一个处理状态比较好?)
若失败,则调用AddTask把Task交回去等待下一次调度。
cello container启动过程
在Container::Execute()函数中,在执行lxc_start之前fork了一个子进程,在子进程中首先调用了CloseInheritedFD,重定向了log,然后调用了lxc_start执行命令,最后调用exit退出。
父进程就先睡了1秒钟,然后调用ContainerStarted函数,这个函数调用了SetResourceLimit限制了Container的资源。限制资源是通过lxc_cgroup_set设置memory.limit_in_bytes以及cpu.shares。
cello container 启动失败上报过程
如果在初始化Container(Init函数)过程中出错,会调用ContainerFinished函数,该函数将Container的状态改为FINISHED,然后向EXECUTOR_STATE_KEY队列发送了一个消息。该消息会由线程ExecutorStatusReceiver接收,该线程根据消息类型生成ContainerState,调用StateHandler处理这个消息,调用MasterService的TaskFinished给master发送消息,同时设置Executor的状态。
cello worker节点任务执行过程
Master调用接口WorkerService的函数StartTask,初始化一个Exectuor插入池中,然后等待StartExecutorSender线程调度。该线程会调用StartExecutor从pool中找到一个等待中的Executor,然后调用Executor的Start函数,该函数会形成一消息发往Executor运行消息队列,并将Executor状态改为执行中。线程StartExecutorReceiver线程会接受到它发的相应消息并处理,具体处理过程为:初始化一个Container结构,调用Container的Init函数初始化一些目录,再调用Executor()函数启动containter(参看cello启动Container过程),并插入Executor池中。
scheduler接收到Cellet回报状态流程
cellet调用TaskStarted,该函数会形成一个StartEvent,并由EventDispather调用Dispatch下发到相应事件队列里面去,这些事件的处理线程是在相应Handler::Handle中取出事件并调用其Handle函数,这些Handle线程由Handler::Start启动,这个Start函数是由scheduler.cpp的main函数注册之后调用。这样应该可以做到动态的添加事件类型。
scheduler 的事件处理
StartEvent,如果是成功启动,就找到这个Task,然后调用FrameworkPool::AddTask,把这个Task加入到运行队列里面去
如果失败,就在Pool里面把这个Task删除掉
FinishEvent,找到相应Task,调用FrameworkPool::RemoveTask,然后在Pool里面把这个任务杀掉
ExecutorState 在collecotor中被处理的流程
状态信息通过心跳中MachineInfo中的子结构list<ExecutorState>发送到collector 服务端,然后被加入到Monitor的机器队列(m_queue中) ,这个队列被Monitor启动的线程周期性取出并解析然后转发到相应的Framework中的ExecutorState队列中,(Monitor里面维护着Framework pool),每一个Framework被启动的时候,会伴随启动一个线程,并安装一个框架整体触发器,这个线程会取出自身的ExecutorState队列中的状态,将其加入到相应ExecutorInMachine结构中,并察看整体的trigger是否满足并触发。每个ExecutorState启动时候,也伴随一个触发器以及一个监控触发器是否触发的线程。
cello添加framework的流程:
用户调用SchedulerService::AddFramewrok,该函数由StandardPool和AutoScalePool分别实现。
在AutoScalePool中,AddFramework中,会创建一个AutoScaleFramework结构,并调用其Init函数,最后将这个结构插入自身的FrameworkPool中。这个Init函数初始化了一个Task,插TaskPool和m_wait_queue中,等待SchedulerProceesor的调度,被形成一个Event,被调用Handle函数。
cello中自动删除Executor的流程:
当Idle触发器触发之后,Collect会调用SchedulerService::DeleteExecutor RPC调用,这个会调用SchedulerService::RemoveTask,该函数会形成一个Remove Event,然后由EventDispatcher分发,并由相应的事件处理线程进行处理,调用其Handle函数,这个函数绑定FrameworkPool::KillTask,再调用Framework::KillTask,最终会产生一个KillActionEvent,再由EventDispatcher进行分发,最后处理,KillActionEvent会调用cellet RPC接口 KillExecutor,详细流程见下。
cellet 杀掉Executor的流程:
CelletService::KillExecutor,会调用ExecutorPool::DeleteExecutor,该函数会绑定并调用Executor::Kill。Kill函数会产生形成一个(KillEvent)消息并发送到EXECUTOR_CONTROL消息队列里面去,将Executor的相应状态改为EXECUTOR_KILLED。这个队列里面的消息会被ExecutorControlReceiver线程调度,形成一个KillEvent,调用ContainerMgr::Instance()->DeleteByTaskId(GetId())删除Executor。