本篇文章给大家分享的是有关如何进行Mesos的实现分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
在这里详细地介绍一下除了mesos资源分配器之外的元数据组织和加载、删除任务的流程。
1 集群元数据管理
Mesos的架构如上图所示,mesos包括两个重要组成部分,首先是一个master进程,它管理运行在各个集群节点上的slave后台进程,而slave进程则负责运行计算框架的计算任务,向master汇报集群节点的资源和计算框架的任务运行状态。
Master的集群元数据管理主要是维护应用程序框架、slave、执行器,计算任务和resource offer之间的对应关系。Slave 则需要维护在slave上运行的所用应用程序框架执行器、任务及其状态。
在mesos的设计中,master是一个非常轻量级地实现,不需要对集群的元数据进行持久化,应用程序框架和slave会向master注册,上报其自身地状态,那么master就可以快速失败和重启。而slave则需要持久化所有的框架信息、执行器信息和任务的状态变化,slave持久化的目的是在slave进程挂掉时候,执行器和任务可以继续运行,以及允许一个重新启动的slave和正在运行的执行器和任务重新连接。
在mesos的master中,Resource offer是多个slave节点上的一组空闲资源。个人理解resource offer其实是代表slave上处于一种中间状态的资源。表示资源分配器选取了这部分资源,并将其发送给应用程序框架,供应用程序框架进行选择,但master还没有收到resource offer的回复(这里回复是指framework选择具体的offer然后下发任务给master)。一旦master收到任务后就会删除resource offer,并更新slave的资源使用状况。
1.1 Master的元数据管理
在master中,需要维护以下一些信息:
1、发送给框架但还没有收到确认的的resource offer,需要在master的内存中进行记录保存。Key为OfferId,value为Offer PB对象的指针。resource offer会在master收到framework下发的任务时,删除对应的offer,更新slave上的资源(这里对framework有个要求,master在resource offer发送了n个offer,那么framework必须回复n个,否则会造成master的资源泄露)。
2、Master需要在内存中维护正在运行的应用程序框架。在应用程序框架中需要记录所有此框架正在运行的任务、已经完成的任务,发送给应用程序框架但还没有收到回复的resource offer、框架的已分配资源、在slave上运行的执行器信息。
3、Master需要在内存中维护所有保活的slave。在slave中需要记录在slave上运行的应用程序框架的执行器、在slave上运行的所有任务,属于slave上的已经发送给应用程序框架但没有收到回应的offer,slave上所有offer占用的资源,已被任务和执行器使用的资源,负责slave心跳保活的process。
4、Master需要在内存中维护framework群组的信息。包括群组的role,属于这个群组的应用程序框架。
以上这些元数据,都不需要进行持久化,在master失败重启后,各个slave和framework重新向master注册后会重新上报和恢复。另外为什么像task和offer会在slave和framework中重复地存储,因为slave和framework都有可能异常,那么需要master在slave或framework异常后处理task和offer的删除和状态更新,比如在framework异常时需要删除所有属于framework的任务和offer。
1.2 Slave上的元数据管理
在Slave上,将应用程序框架和框架的执行器进行抽象,分别用类Framework和Executor来表示,在Framework中维护此应用程序框架在这个slave上运行的执行器,而执行器则维护着所有在此执行器上运行的任务信息,并持久每一个任务的状态变化。如下图所示:
Framework的执行器维护着所有在执行器中运行的处于各种状态的任务,执行器有四个队列,分别对应四种不同状态的任务,这四个队列如下:
LinkedHashMap<TaskID, TaskInfo> queuedTasks; //任务已经下发,但执行器还没启动,所以任务暂时放在这个队列中。
LinkedHashMap<TaskID, Task*> launchedTasks; // 已经在执行器中运行的任务
LinkedHashMap<TaskID, Task*> terminatedTasks; //已经结束(master向slave下发删除任务的命令)但没有释放的任务
boost::circular_buffer<Task> completedTasks; //已经完成的任务,放在circular_buffer中延迟释放
在framework中还维护着应用程序框架所有已经下发到slave上但处于启动状态的执行器和任务的映射。为什么要维护这么个映射呢,因为mesos采用了libprocess作为并发框架,启动执行器运行任务是异步执行,在这个过程中如果框架和执行器被删除,那么需要保证框架和执行器的持久化目录不被删除,所以维护这个映射来做一些异常处理,通过延后垃圾回收的方式回收这些已经被删除的框架和执行器的目录文件。
Slave持久化的数据分成五个部分,分别是slave的信息、framework的信息、executor的信息、任务的信息,和任务的状态变化。
1、 slave信息的持久化:在slave成功向master注册后,收到SlaveRegisteredMessage信息后的处理函数registered会对slave的信息进行持久化。
2、 framework和executor信息的持久化:framework和执行器的持久化都在其构造函数里完成。在加载新任务(runTask)时,会创建新的framework和executor。
3、 任务的持久化:在执行器已经在运行的情况下,会在加载任务时进行持久化;或者执行器正在注册,则在任务进行排队时会进程持久化。
4、 任务的状态变化持久化:任务的状态变化的持久化稍微复杂一点。slave用三个类实现了对所有运行在slave上的task的状态管理,分别是StatusUpdateManager、StatusUpdateManagerProcess、StatusUpdateStream这三个类;StatusUpdateManager仅仅是一个wrapper,StatusUpdateManagerProcess管理所有在slave上运行的框架的task状态更新,在收到状态更新后先进行持久化,然后向master发送状态更新,接收scheduler的状态更新确认,再对确认进行持久化。StatusUpdateStream完成task的状态更新和确认的持久化工作。Task的状态更新有两种,一种是update,是由执行器向slave发送的状态更新;另一种是scheduler向slave发送的task状态确认。这两种都需要进行持久化。在StatusUpdateStream维持着三个数据结构用于维护这些状态:
hashset<UUID> received;
hashset<UUID> acknowledged;
std::queue<StatusUpdate> pending;
用于记录task的状态更新的执行状态,received中保存的是slave接收到执行器发送的task状态更新。Acknowleged是scheduler向slave发送确认的task状态更新。Pending中是已经接收到但没有进行确认的task状态更新。
下图是这三个类的类图:
2 加载task和删除task的流程图
加载Task的流程图如下:
1、master进行resource offer:master在初始化、framework注册、slave注册时都会进行resource offer,而且除了以上事件之外,master会定期地进行resource offer。Master资源调度算法见我的另外一篇博客。
2、framework在接收到ResourceOffersMessage信令后,会调用scheduler的resourceOffers接口,scheduler要选择自己需要的资源,然后调用SchedulerDriver的launchTasks接口,向master下发任务,SchedulerDriver会调用SchedulerProcess的launchTasks接口,把任务组装在LaunchTasksMessage中,进行发送。SchedulerProcess负责接收和发送与master的信令交互。Scheduler是实现具体具体框架的业务逻辑,SchedulerDriver是对SchedulerProcess和Scheduler进行解耦。Framework相关的类图如下所示:
3、master在收到LaunchTasksMessage,会在内存中创建维护执行器和任务的信息,然后向slave下发任务,下发任务的信令为RunTaskMessage。
4、slave在加载任务时,需要做的工作比较多;如果task对应的框架或执行器没有被创建,那么需要创建一个新的框架并持久化框架的ID和信息,或者让isolator分配资源并启动一个执行器进程,执行器进程启动后会向slave进行注册。加载任务时会先对task信息进行持久化,然后向执行器的数据结构中添加task信息。如果此时执行器进程正在向slave注册(slave中的执行器状态为REGISTERING),那么会将先task进行放在队列中缓存。否则会向执行器进程发送RunTaskMessage信令,让执行器运行task。
5、如果执行器刚启动,则启动之后根据传入的slave的IP和端口,连接slave;然后发送RegisterExecutorMessage信令,向slave进行注册。
6、slave在收到RegisterExecutorMessage,更新执行器的状态,如果支持持久化,那么将执行器的pid进行持久化;如果缓存队列中有等待处理的task,则执行器添加这些task,使用isolator来分配执行器的资源。回复ExecutorRegisteredMessage给执行器进程,然后将所有缓存队列中等待处理的task打包在RunTaskMessage信令中,发送给执行器进程来执行这些task。清空执行器的缓存队列。
7、执行器进程在接收到RunTaskMessage信令,会调用执行器的抽象接口launchTask,来加载任务。
8、执行器进程在执行任务过程中任务出错,或者任务结束都需要更新任务状态,发送StatusUpdateMessage信令给slave。
9、slave在收到StatusUpdateMessage信令后,会更新任务信息,并将任务状态更新进行持久化(由StatusUpdateManager这个类完成),然后向master转发StatusUpdateMessage信令,传递任务的状态更新。如果task的状态为failed、killed或者finished,则执行器会重新调整使用的资源,由isolator为执行器重新分配资源。
10、执行器进程收到任务状态更新的应答。
11、master收到StatusUpdateMessage后,会更新任务状态信息,并向framework转发任务状态更新。如果task已经结束(为failed、killed以及finished),则从master的内存中清除这些被删除的任务,
12、framework收到task状态更新后,会调用scheduler的statusUpdate接口。如果task已经结束,则需要框架进行一些清理工作。
删除任务的流程图如下:
删除任务则较为简单,删除任务是由framework发起的,killTaskMessage沿着framework、master、slave、执行器这一条链路上进行传递,但在处理killTaskMessage信令时,正常情况下都不会直接删除task,而是在后续处理StatusUpdateMessage时,检测到task状态为failed、killed和finished才会真正删除task。
以上就是如何进行Mesos的实现分析,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注天达云行业资讯频道。