怎样在mesos上开发

如果只是执行shell命令或docker image,使用CommandExecutor可以简化开发。当启动任务时,指定CommandInfo而不是ExecutorInfo可以简化开发。

开发时,很多类型、消息定义可以查阅include/mesos/mesos.proto

通信

mesos部件间通信使用libprocess库,其消息是immutable,通信的API包括以下几类:

  • Scheduler API:framework调度器与master之间通信,内部通信通常只由SchedulerDriver使用
  • Executor API:executor与slave之间通信
  • 内部API:master与slave之间通信
  • Operator API:由web UI操作者使用,与其他API不同的是,这类API通常是同步的

发送消息,是做一次HTTP POST请求,消息数据作为HTTP请求的body发送,例如以下是运行在10.0.1.7:53523的scheduler发送给framework的注册消息头:

POST /master/mesos.internal.RegisterFrameworkMessage HTTP/1.1
User-Agent: libprocess/scheduler(1)@10.0.1.7:53523

回复消息:

POST /scheduler(1)/mesos.internal.FrameworkRegisteredMessage HTTP/1.1
User-Agent: libprocess/[email protected]:5050

framework

可以在源代码目录MESOS_HOME/src/examples/看到FrameworkScheduler的例子。通过例子来理解MesosFrameworkScheduler并选择你喜欢语言进行执行。RENDLER提供了以C++,Go,Haskell,Java,Python和Scala语言所实现的Framework例子。

Scheduler API

你可以用C、C++、Java/Scala或者Python语言编写一个框架Scheduler,它需要继承Scheduler类(见下面Scheduler API)。Scheduler应当创建一个SchedulerDriver(负责Scheduler和Mesos master的通信),然后调用SchedulerDriver.run()函数。

用framework schedulers程序实现的回调接口。 声明如下代码位于:MESOS_HOME/include/mesos/scheduler.hpp 。

/* 
* 空的虚拟的析构函数 (需要把析构函数实例化成子类).
*/ 
virtual ~Scheduler() {}
 /* 
* 函数在当Scheduler成功在MesosMaster中注册时被调用。
* FrameworkID是在Framework中由Master生成一个唯一的ID,用于区别其他Scheduler。
* MasterInfo以参数的形式提供当前的Master IP地址和端口。
*/
 virtual void registered(SchedulerDriver* driver,
                       const FrameworkID& frameworkId, 
                        const MasterInfo& masterInfo) = 0;
 /* 
* 函数在Scheduler再次在新当选的Master注册时被调用。
*只有当Scheduler以前被注册过时调用。
* MasterInfo以参数的形式表示新当选的Master的更新信息。
*/ 
virtual void reregistered(SchedulerDriver* driver, 
                        const MasterInfo& masterInfo) = 0;
 /* 
* 函数在Scheduler与Master变成"无链接"时被调用。
* (举例来说, 当前Master关闭并由其他的Master接管)。
*/ 
virtual void disconnected(SchedulerDriver* driver) = 0; 
/*
* 函数在资源已经被提供给这个Framework时被调用。最简单的offer仅包含一个简单slave的资源。 
* 这些资源以一个offer的形式打包提供给当前Framework对象,除非发生异常情况,则不在提交。
* 第一种当前或者某个Framework拒绝了这些资源,才能够再次提交offer。
* (请查看 SchedulerDriver::launchTasks) 或者第二种情况取消了这些资源。
* (请查看 Scheduler::offerRescinded)。
* 注意:资源可能在同一时间提交给一个或者多个Framework(根据分配器的分配情况)。 * 如果上面的事情发生, 首先拿到offer的Framework将会使用这些资源来启动Tasks,导致其他Tasks获取 
* offer的Framework取消这些资源的使用(或者某个Framework已经使用这些资源启动了Tasks,
* 这些Tasks将会伴随着TASK_LOST状态而失败,并发送过多的消息通知)。 
*/ 
virtual void resourceOffers(SchedulerDriver* driver,
                           const std::vector<Offer>& offers) = 0; 
/*
* 函数在某个offer不在有效时被调用。(举例来说, 节点不可用或者资源被其他Framework的offer占用)。 
* 如下发生以下情况offer均不会撤销 (举例来说, 丢弃信息,Framework运行失败,等等。),
* 当Framework尝试启动那些没有有效offer的Tasks时,Framework会收到那些Tasks发送TASK_LOST的状态更新 
* (请查看Scheduler::resourceOffers). 
*/ virtual void offerRescinded(SchedulerDriver* driver, 
                            const OfferID& offerId) = 0; 
/*
* 函数在一个Tasks的状态发生变化时被调用。(举例来说, 一个节点(slave)丢失并且Tasks丢失, 
* 一个Tasks完成并且Executors发送了一个状态更新回话,等等)。 如果使用隐式定义implicit 
* acknowledgements, 以 _acknowledges_ 的收据作为这个状态的更新作为回调函数返回! 
* 如果发生Scheduler无论何种原因在回调函数的时候终止(或者进程退出)另一个状态更新将会被提交 
* (注意,无论如何,如果slave发送状态更新是丢失或者失败。在那段时间是不正确的)。
* 如果使用的是显示explicit acknowledgments,Scheduler必须在驱动中知道这个状态。
*/ 
virtual void statusUpdate(SchedulerDriver* driver,
                         const TaskStatus& status) = 0; 
/* 
* 函数在当Executors发送消息时被调用。 
* 这些消息是尽力服务:在任何可靠的方式下,绝不期望Framework消息会被重新提交。 */ 
virtual void frameworkMessage(SchedulerDriver* driver,
                               const ExecutorsID& ExecutorsId,
                               const SlaveID& slaveId, 
                                const std::string& data) = 0; 
/*
* 函数在当某个slave确定不能找到时被调用。(举例来说,设备故障,网络隔离)。
* 绝大部分Framework会以在新的slave上重新启动所有Tasks的方式进行调度。
*/ 
virtual void slaveLost(SchedulerDriver* driver, 
                     const SlaveID& slaveId) = 0; 
/* 
* 函数在Executors退出或者中断时被调用。注意:任何Tasks的运行将会自动生成TASK_LOST的状态更新。
*/ 
virtual void ExecutorsLost(SchedulerDriver* driver, 
                        const ExecutorsID& ExecutorsId, const SlaveID& slaveId, 
                         int status) = 0; 
/* 
* 函数在一个未被Scheduler或者Scheduler驱动不能捕获的错误发生时被调用。
* Scheduler驱动将会在这个回调函数执行之前执行。
*/
 virtual void error(SchedulerDriver* driver, 
                    const std::string& message) = 0;

Scheduler Driver API

Scheduler Driver负责scheduler的生命周期管理(start, stop, or wait to finish)及与master交互(启动/杀死任务等)

// 启动scheduler driver。必须最先被调用
virtual Status start();

// 停止scheduler driver。如果设置了'failover'标志为false,表示本framework永远不要与mesos重连。 
// Mesos将unregister the framework并shutdown所有tasks and executors. 
// 若'failover'是true,所有executors及tasks将继续运行以允许scheduler重连。
virtual Status stop(bool failover = false);

// Aborts the driver,之后scheduler的回调函数都不会被调用
// abort and stop的语义是区分的,代码能够检测到aborted driver, and
// 如果需要能够立刻启动另一个driver,'stop()'并非在'abort()'中自动被调用
virtual Status abort();

// 等待driver stopped或aborted, 可能会将当前线程无限期阻塞。
// 本函数的返回状态可以用来判断driver是否aborted
virtual Status join();

// 启动并立即joins the driver.
virtual Status run();

// 向mesos请求资源(请求格式参见mesos.proto,例如从指定的slaves请求资源。
// 可用的资源由Scheduler::resourceOffers回调函数异步给出.
virtual Status requestResources(const std::vector<Request>& requests);

// 启动给定的任务集。任何未用的资源会被declined. 指定的filters是作用在所有未使用的资源
// 注意所有offer必须属于同一个slave。使用空的tasks集合调用本函数将declines所有offers
virtual Status launchTasks(
    const std::vector<OfferID>& offerIds,
    const std::vector<TaskInfo>& tasks,
    const Filters& filters = Filters());

// Kills the specified task. Note that attempting to kill a task is
// currently not reliable. If, for example, a scheduler fails over
// while it was attempting to kill a task it will need to retry in
// the future. Likewise, if unregistered / disconnected, the request
// will be dropped (these semantics may be changed in the future).
virtual Status killTask(const TaskID& taskId);

// Accepts the given offers and performs a sequence of operations on
// those accepted offers. See Offer.Operation in mesos.proto for the
// set of available operations. Any remaining resources (i.e., those
// that are not used by the launched tasks or their executors) will
// be considered declined. Note that this includes resources used by
// tasks that the framework attempted to launch but failed (with
// `TASK_ERROR`) due to a malformed task description. The specified
// filters are applied on all unused resources (see mesos.proto for
// a description of Filters). Available resources are aggregated
// when multiple offers are provided. Note that all offers must
// belong to the same slave.
virtual Status acceptOffers(
    const std::vector<OfferID>& offerIds,
    const std::vector<Offer::Operation>& operations,
    const Filters& filters = Filters());

// Declines an offer in its entirety and applies the specified
// filters on the resources (see mesos.proto for a description of
// Filters). Note that this can be done at any time, it is not
// necessary to do this within the Scheduler::resourceOffers
// callback.
virtual Status declineOffer(
    const OfferID& offerId,
    const Filters& filters = Filters());

// Removes all filters previously set by the framework (via
// launchTasks()). This enables the framework to receive offers from
// those filtered slaves.
virtual Status reviveOffers();

// Inform Mesos master to stop sending offers to the framework. The
// scheduler should call reviveOffers() to resume getting offers.
virtual Status suppressOffers();

// Acknowledges the status update. This should only be called
// once the status update is processed durably by the scheduler.
// Not that explicit acknowledgements must be requested via the
// constructor argument, otherwise a call to this method will
// cause the driver to crash.
virtual Status acknowledgeStatusUpdate(const TaskStatus& status);

// Sends a message from the framework to one of its executors. These
// messages are best effort; do not expect a framework message to be
// retransmitted in any reliable fashion.
virtual Status sendFrameworkMessage(
    const ExecutorID& executorId,
    const SlaveID& slaveId,
    const std::string& data);

// Allows the framework to query the status for non-terminal tasks.
// This causes the master to send back the latest task status for
// each task in 'statuses', if possible. Tasks that are no longer
// known will result in a TASK_LOST update. If statuses is empty,
// then the master will send the latest status for each task
// currently known.
virtual Status reconcileTasks(const std::vector<TaskStatus>& statuses);

Executor API

/*
 * 函数在执行器驱动第一次成功链接到Mesos时被调用。特别的是,
 * 调度器可以把一些数据内容传递给执行器的FrameworkInfo.ExecutorInfo数据区。
 */
virtual void registered(ExecutorDriver* driver,
                        const ExecutorInfo&amp; executorInfo,
                        const FrameworkInfo&amp; frameworkInfo,
                        const SlaveInfo&amp; slaveInfo) = 0;

/*
 * 函数在某节点重启后再次注册执行器时被调用。
 */
virtual void reregistered(ExecutorDriver* driver,
                          const SlaveInfo&amp; slaveInfo) = 0;

/*
 * 函数在节点要发送的执行器"无法链接"时调用。(举例来说, 节点由于升级导致的重启)。
 */
virtual void disconnected(ExecutorDriver* driver) = 0;

/*
 * 函数在执行器要启动任务时调用。(通过Scheduler::launchTasks进行初始化)。
 * 注意:任务必须属于线程、进程、或者简单的计算,否则直到执行器返回回调时,
 * 没有任何回调函数会被调用。
 */
virtual void launchTask(ExecutorDriver* driver,
                        const TaskInfo&amp; task) = 0;

/*
 * 函数在调度器内正在运行的任务要终止时调用。(通过 SchedulerDriver::killTask)。
 * 注意:函数将代表执行器发送没有状态更新。执行器需要对创建新的任务状态负责
 * (换种说明, TASK_KILLED)并执行ExecutorDriver::sendStatusUpdate。
 */
virtual void killTask(ExecutorDriver* driver, const TaskID&amp; taskId) = 0;

/*
 * 函数在计算框架要传递给执行器信息时调用。这些消息是唯一正确的途径。
 * 不要指望计算框架的信息以任何其他的可靠的方式重新提交。
 */
virtual void frameworkMessage(ExecutorDriver* driver,
                              const std::string&amp; data) = 0;

/*
 * 函数在执行器需要终止所有现在运行任务时被调用。
 * 注意:函数在Mesos确定执行器将要终止所有的任务时,执行器不会发送终止状态的更新
 * (举例来说, TASK_KILLED, TASK_FINISHED,TASK_FAILED, 等)而会创建TASK_LOST状态更新。
 */
virtual void shutdown(ExecutorDriver* driver) = 0;

/*
 * 函数在执行器或者执行器驱动发生了一个致命性的错误是时被调用。驱动会在函数的回调之前终止。
 */
virtual void error(ExecutorDriver* driver, const std::string&amp; message) = 0;

安装Framework

你需要把Framework放在集群的所有节点(slaves)。如果你运行需要HDFS,你可以把你的执行器放到HDFS。你可以通过ExecutorInfo参数把执行器放到HDFS这件事情告诉MesosSchedulerDriver的构造器。(举例来说:请示例代码查看src/examples/java/TestFramework.java)。

ExecutorInfo 是协议缓存信息类(在include/mesos/mesos.proto中进行定义), 并且你可以设置URI字段,例如“HDFS://path/to/executor/”. 或者, 你可以通过 frameworks_home 的配置项 (在这里进行定义: MESOS_HOME/frameworks) 告诉mesos节点守护器你所制定的执行器所存储的位置 (举例来说 所有节点(slave)均使用的NFS挂载方式), 然后设置ExecutorInfo为相对路径, 节点(slave)将预先提供frameworks_home的相对路径的值。

你一旦确定执行器在mesos的那些节点可以运行,你需要运行在Mesos管理器中注册的调度器,然后开始接收资源offer!

模块

模块提供了一种简单的方法,可以使Mesos轻松的被第三方模块扩展,而第三方模块却不必知道所有Mesos的内部细节。

调用Mesos的模块

命令行标志--modules 用于Mesos master ,slave 和测试指定的模块列表的加载情况和在内部子系统的可用情况。

使用 --modules=filepath 来指定列表模块 ,所指的文件中应包含被JSON格式化的字符串, 。“filepath”的格式应该是‘file:///path/to/file’ 或 ‘/path/to/file’.的形式。

使用--modules="{...}" 在命令行指定模块列表。

JSON字符串示例:

  • 加载库libfoo.so ,其中包含两个模块org_apache_mesos_bar 和org_apache_mesos_baz。
        {
     "libraries": [
       {
         "file": "/path/to/libfoo.so",
         "modules": [
           {
             "name": "org_apache_mesos_bar",
           },
           {
             "name": "org_apache_mesos_baz"
           }
         ]
       }
     ]
    }
    
  • 从foo加载模块org_apache_mesos_bar和传递命令行参数X和Y值(模块加载org_apache_mesos_baz没有任何命令行参数):
    {
     "libraries": [
       {
         "name": "foo",
         "modules": [
           {
             "name": "org_apache_mesos_bar"
             "parameters": [
               {
                 "key": "X",
                 "value": "Y",
               }
             ]
           },
           {
             "name": "org_apache_mesos_baz"
           }
         ]
       }
     ]
    }
    
  • 在命令行中指定
    --modules='{"libraries":[{"file":"/path/to/libfoo.so", "modules":[{"name":"org_apache_mesos_bar"}]}]}'
    

库名

对于每一个library,至少有一个的“file”或“name”参数必须被指定。“file”参数可能指一个文件名(例如“libfoo.so”),相对路径(如“myLibs / libfoo.so”)或绝对路径(例如“/home/mesos/lib/libfoo.so”)。“name”参数是指库名称(如“foo”)。如果“name”被指定了,它会在当前平台上自动改为一个合适的库名称(如在Linux上:“foo”自动改为“libfoo.so”。在OS X 改为“libfoo.dylib”)。 如果库路径没有在“file”中指定参数,库就会搜索标准库的路径或目录:LD_LIBRARY_PATH(在OS X上是:DYLD_LIBRARY_PATH)。 如果“file”和“name”两个都指定了,“name”将被忽略。

可用的各种模块类型

分配器

Mesos master分配器定期确定哪些框架应该提供集群的可用资源。

在Mesos master加载自定义分配器,你需要:

  • 介绍其给Mesos master,通过使用 --modules配置,
  • 选择它作为分配器通过 --allocator。 例如,下面的命令将运行Mesos master,其内包含ExternalAllocatorModule:
    ./bin/mesos-master.sh --work_dir=m/work --modules="file://<modules-including-allocator>.json" --allocator=ExternalAllocatorModule
    

匿名模块

匿名模块不会收到任何回调, 它与他们的父进程共存。与其他命名模块不同的是,一个匿名模块并不直接提供或替代基本功能(如一个隔离器模块)。和装饰模块也不同,它也不直接提供添加或注入数据。匿名模块不需要任何特定的选择器(标志),Mesos master或slave通过--modules, 他们会立即被实例化

验证模块

验证模块允许第三方快速开发和插件的新身份验证方法。这样的模块可以支持PAM(LDAP、MySQL NIS,UNIX)对身份的验证。

Hook

类似于Apache web服务器模块,hooks允许开发一些功能,这些功能可以与内部组件紧密结合,但又不完全适合抽象为模块,只是定义了一些操作,这就是所谓的hooks。

可用的hook API定义在hook.hpp 。每个hook 定义了插入点和可用的上下文。一个例子就是传递给master 的LaunchTaskHook的任务信息。

一些hook可以获得一个对象(例如TaskInfo)并返回对象的全部或部分信息(例如task labels),这样hook可以动态调整其内容。这些hook被称为decorators。

在Mesos中加载一个hook,你需要:

  • --modules引入相关模块
  • --hooks标志选择hook

例如,这样启动agent:

./bin/mesos-agent.sh --master=<IP>:<PORT> --modules="file://<path-to-modules-config>.json" --hooks=TestTaskHook

隔离器

隔离器模块支持试验专门隔离和监视功能。这些例子可以是第三方的资源隔离机制的GPGPU硬件,网络,等等。

Master Contender and Detector

可以实现定制的master leader的选择及检测机制,而不是依赖于缺省的Zookeeper。

例如模块可以使用etcd或consul的服务。

要加载这种模块,需要:

  • master启动时指定--modules
  • master启动时使用--master_contender--master_detector标志
  • slave启动时使用--master_detector标志

例如:

./bin/mesos-master.sh --modules="file://<path-to-modules-config>.json" --master_contender=org_apache_mesos_TestMasterContender --master_detector=org_apache_mesos_TestMasterDetector
./bin/mesos-slave.sh --modules="file://<path-to-modules-config>.json" --master_detector=org_apache_mesos_TestMasterDetector

results matching ""

    No results matching ""