[+]文章目录

在本文档中,我们把Mesos程序集称为计算框架。

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

创建框架调度器(Framework Scheduler)

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

调度器API(Scheduler API)

声明如下代码位于:MESOS_HOME/include/mesos/scheduler.hpp

/*
 * 空的虚拟的析构函数 (需要把析构函数实例化成子类).
 */
virtual ~Scheduler() {}

/*
 * 函数在当调度器成功在Mesos管理器中注册时被调用。
 * FrameworkID是在框架中由管理器生成一个唯一的ID,用于区别其他调度器。
 * MasterInfo以参数的形式提供当前的管理器IP地址和端口。
 */
virtual void registered(SchedulerDriver* driver,
                        const FrameworkID& frameworkId,
                        const MasterInfo& masterInfo) = 0;

/*
 * 函数在调度器再次在新当选的管理器注册时被调用。
 * MasterInfo以参数的形式囊括新当选的管理器信息。
 */
virtual void reregistered(SchedulerDriver* driver,
                          const MasterInfo& masterInfo) = 0;

/*
 * 函数在调度器与管理器变成"无链接"时被调用。
 * (举例来说, 当前管理器关闭并由其他的管理接管)。
 */
virtual void disconnected(SchedulerDriver* driver) = 0;

/*
 * 函数在资源已经被提供给计算框架时被调用。最简单的offer仅包含一个简单slave的资源。
 * 这些资源以一个offer的形式打包提供给当前计算框架对象,除非发生异常情况,则不在提交。
 * 第一种当前或者某个计算框架拒绝了这些资源,才能够再次提交offer。
 * (请查看 SchedulerDriver::launchTasks) 或者第二种情况取消了这些资源
 * (请查看 Scheduler::offerRescinded)。
 * 注意:资源可能在同一时间提交给一个或者多个计算框架(根据分配器的分配情况)。
 * 如果上面的事情发生, 首先拿到offer的计算框架将会使用这些资源来启动任务,导致后获取
 * offer的计算框架取消这些资源的使用(或者某个计算框架已经使用这些资源启动了任务,
 * 这些任务将会伴随着TASK_LOST状态而失败,并发送过多的消息通知)。
 */
virtual void resourceOffers(SchedulerDriver* driver,
                            const std::vector<Offer>& offers) = 0;

/*
 * 函数在某个offer不在有效时被调用。(举例来说, 节点不可用或者资源被其他计算框架的offer占用)。
 * 如下发生以下情况offer均不会撤销 (举例来说, 丢弃信息,计算框架运行失败,等等。),
 * 当计算框架尝试启动那些没有有效offer的任务时,计算框架会收到那些任务发送TASK_LOST的状态更新
 * (请查看Scheduler::resourceOffers).
 */
virtual void offerRescinded(SchedulerDriver* driver,
                            const OfferID& offerId) = 0;

/*
 * 函数在一个任务的状态发生变化时被调用。(举例来说, 一个节点(slave)丢失并且任务丢失,
 * 一个任务完成并且执行器发送了一个状态更新回话,等等)。 如果使用隐式定义implicit
 * acknowledgements, 以 _acknowledges_ 的收据作为这个状态的更新作为回调函数返回!
 * 如果发生调度器无论何种原因在回调函数的时候终止(或者进程退出)另一个状态更新将会被提交
 * (注意,无论如何,如果slave发送状态更新是丢失或者失败。在那段时间是不正确的)。
 * 如果使用的是显示explicit acknowledgments,调度器必须在驱动中知道这个状态。
 */
virtual void statusUpdate(SchedulerDriver* driver,
                          const TaskStatus& status) = 0;

/*
 * 函数在当执行器发送消息时被调用。
 * 这些消息是尽力服务:在任何可靠的方式下,绝不期望计算框架消息会被重新提交。
 */
virtual void frameworkMessage(SchedulerDriver* driver,
                              const ExecutorID& executorId,
                              const SlaveID& slaveId,
                              const std::string& data) = 0;

/*
 * 函数在当某个slave确定不能找到时被调用。(举例来说,设备故障,网络隔离)。
 * 绝大部分计算框架会以在新的slave上重新启动所有任务的方式进行调度。
 */
virtual void slaveLost(SchedulerDriver* driver,
                       const SlaveID& slaveId) = 0;

/*
 * 函数在执行器退出或者中断时被调用。注意:任何任务的运行将会自动生成TASK_LOST的状态更新。
 */
virtual void executorLost(SchedulerDriver* driver,
                          const ExecutorID& executorId,
                          const SlaveID& slaveId,
                          int status) = 0;

/*
 * 函数在一个未被调度器或者调度器驱动不能捕获的错误发生时被调用。
 * 调度器驱动将会在这个回调函数执行之前执行。
 */
virtual void error(SchedulerDriver* driver, const std::string& message) = 0;

创建计算框架执行器Framework Executor

你的计算框架执行器(Framework Executor)必须从Executor类继承。它必须覆盖launchTask()函数。你需要在Mesos决定在那些节点(slave)运行你的执行器,并在执行器内部使用 $MESOS_HOME 环境变量。

执行器 API(Executor API)

声明如下代码位于:MESOS_HOME/include/mesos/executor.hpp

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

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

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

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

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

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

安装计算框架Install your 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!

标签Labels

可以在FrameworkInfo, TaskInfo, DiscoveryInfo和TaskStatus信息中找到标签(Labels)。计算框架和模块的编写者可以在Mesos内使用标签来标记和传递非机构化的信息。标签是以key-value的自由格式提供给计算框架调度器或标签装饰钩子。下面是protobuf的标签定义:

optional Labels labels = 11;
/**
 * 标签集合。
 */
message Labels {
    repeated Label labels = 1;
}

/**
 * 以Key,value的形式来自由存储用户数据。
 */
message Label {
  required string key = 1;
  optional string value = 2;
}

标签并不是Mesos给它自己进行解释,但作为管理器和节点之间的终点状态。此外,执行器和调度器在TaskInfo和TaskStatus以编程的方式进行标签解析。下面是列举了两个对标签的例子 ("environment": "prod" 和 "bananas": "apples")可以从管理器状态终点进行获取。

$ curl http://master/state.json
...
{
  "executor_id": "default",
  "framework_id": "20150312-120017-16777343-5050-39028-0000",
  "id": "3",
  "labels": [
    {
      "key": "environment",
      "value": "prod"
    },
    {
      "key": "bananas",
      "value": "apples"
    }
  ],
  "name": "Task 3",
  "slave_id": "20150312-115625-16777343-5050-38751-S0",
  "state": "TASK_FINISHED",
  ...
},

发现服务Service discovery

当你的计算框架注册了执行器,并启动了任务,可以给发现服务提供额外的信息。这些信息存储在Mesos管理器伴随着其他重要信息 例如节点(slave)正在运行的任务。在Mesos集群运行多计算框架多任务时,发现服务系统可以以编程的方式准备号纠正并恢复创建DNS索引、配置代理、或者更新不一致的存储信息。

DiscoveryInfo选项信息将会传递给TaskInfo和ExecutorInfo,声明如下代码位于:MESOS_HOME/include/mesos/mesos.proto

message DiscoveryInfo {
  enum Visibility {
    FRAMEWORK = 0;
    CLUSTER = 1;
    EXTERNAL = 2;
  }

  required Visibility visibility = 1;
  optional string name = 2;
  optional string environment = 3;
  optional string location = 4;
  optional string version = 5;
  optional Ports ports = 6;
  optional Labels labels = 7;
}

显而易见的,通知发现服务器系统应当发现已经通知过的Key参数。我们现在列举三个不同的案例:

任务不除了所属的计算框架以外的不应当被发现。
任务应当在所运行的Mesos集群中的所有计算框架发现,而不是在外部被发现。
任务应当无误的发现。
大量的发现服务系统提供附加的管理可见的字段。(举例来说,系统中基于代理的ACL,DNS的安全扩展,VLAN或者子网选择)不打算使用可见的资源来管理这些功能。服务发现系统重新从管理器获取任务或者执行器信息,这种方式解决没有DiscoveryInfo如何获取任务。举例,任务不会对其他计算框架可见。(等价于 visibility=FRAMEWORK)或者对所有计算框架可见(等价于 visibiility=CLUSTER)。

名称字段的数据格式是字符串,字符串可以保证服务发现系统通过名字的形式发现任务。典型的名称字段是提供有效的域名。如果名称无法提供,则需要服务发现系统在taskInfo或者其他信息中的名称字段来为任务创建名称。

环境变量、地址信息、和版本等字段在大型部署中提供了第一类的支持,对象的属性相同但是在不同地方应用的相似服务。环境可以接收如吃产品/质量检查/开发,位置字段可以接收如下值:EAST-US/WEST-US/EUROPE/AMEA, 以及版本字段可以接收如下值v2.0/v0.9。发现系统需要正确的把这些字段提供给服务发现系统。

端口字段允许计算框架定义任务的监听端口并明确名称的功能,端口字段是可以再次提交并使用网络的第四层通讯协议(TCP,UDP或者其他)。举例,Cassandra的任务定义如下端口"7000,Cluster,TCP", "7001,SSL,TCP", "9160,Thrift,TCP", "9042,Native,TCP", 和 "7199,JMX,TCP"。由服务发现系统以适当形式的协议把潜在的把DiscoveryInfo的名称字段进行绑定。

标签字段允许计算框架以key/value对的格式传递主观标签给服务发现系统。注意:通过这些字段传递的任何事情,是无法保障执行移动到下一步。虽然如此,字段提供扩展性。这些共同使用的字段允许我们确认需要请求第一类支持的例子。

@2015 译者:抢小孩糖吃


« 前一篇