Перейти к основному содержимому

Путеводитель по Apache Mesos

· 13 мин. чтения

1. Обзор

Обычно мы развертываем различные приложения на одном и том же кластере машин. Например, в настоящее время принято иметь распределенный механизм обработки, такой как Apache Spark или Apache Flink , с распределенными базами данных, такими как Apache Cassandra , в одном кластере.

Apache Mesos — это платформа, позволяющая эффективно распределять ресурсы между такими приложениями.

В этой статье мы сначала обсудим несколько проблем распределения ресурсов в приложениях, развернутых в одном кластере. Позже мы увидим, как Apache Mesos обеспечивает лучшее использование ресурсов между приложениями.

2. Совместное использование кластера

Многим приложениям необходимо совместно использовать кластер. По большому счету, есть два распространенных подхода:

  • Разделите кластер статически и запустите приложение на каждом разделе
  • Выделить набор машин для приложения

Хотя эти подходы позволяют приложениям работать независимо друг от друга, они не обеспечивают высокого уровня использования ресурсов.

Например, рассмотрим приложение, которое работает только в течение короткого периода времени, за которым следует период бездействия. Теперь, поскольку мы выделили статические машины или разделы для этого приложения, у нас есть неиспользованные ресурсы в течение неактивного периода.

Мы можем оптимизировать использование ресурсов, перераспределяя свободные ресурсы в период неактивности другим приложениям.

Apache Mesos помогает с динамическим распределением ресурсов между приложениями.

3. Апач Месос

При обоих подходах к совместному использованию кластера, которые мы обсуждали выше, приложения знают только о ресурсах определенного раздела или машины, на которой они работают. Однако Apache Mesos предоставляет приложениям абстрактное представление обо всех ресурсах в кластере.

Как мы вскоре увидим, Mesos действует как интерфейс между машинами и приложениями. Он предоставляет приложениям доступные ресурсы на всех машинах в кластере. Эта информация часто обновляется, чтобы включить ресурсы, высвобождаемые приложениями , достигшими состояния завершения. Это позволяет приложениям принимать наилучшие решения о том, какую задачу выполнять на какой машине.

Чтобы понять, как работает Mesos, давайте взглянем на его архитектуру :

./d22b92fc6990e6f265de76da4156ee64.jpg

Это изображение является частью официальной документации Mesos ( источник ). Здесь Hadoop и MPI — это два приложения, которые совместно используют кластер.

Мы поговорим о каждом показанном здесь компоненте в следующих нескольких разделах.

3.1. Мастер Месос

Мастер является основным компонентом в этой настройке и хранит текущее состояние ресурсов в кластере. Кроме того, он действует как оркестратор между агентами и приложениями, передавая информацию о таких вещах, как ресурсы и задачи.

Поскольку любой сбой в мастере приводит к потере состояния ресурсов и задач, мы развертываем его в конфигурации высокой доступности. Как видно на диаграмме выше, Mesos развертывает резервные основные демоны вместе с одним лидером. Эти демоны полагаются на Zookeeper для восстановления состояния в случае сбоя.

3.2. Агенты Месос

Кластер Mesos должен запускать агент на каждой машине. Эти агенты периодически сообщают о своих ресурсах мастеру и, в свою очередь, получают задачи, выполнение которых запланировано приложением . Этот цикл повторяется после завершения или потери запланированной задачи.

В следующих разделах мы увидим, как приложения планируют и выполняют задачи на этих агентах.

3.3. Мезо Фреймворки

Mesos позволяет приложениям реализовать абстрактный компонент, который взаимодействует с Мастером, чтобы получать доступные ресурсы в кластере и, кроме того , принимать решения о планировании на их основе. Эти компоненты известны как фреймворки.

Каркас Mesos состоит из двух подкомпонентов:

  • Планировщик — позволяет приложениям планировать задачи на основе доступных ресурсов на всех агентах.
  • Executor — работает на всех агентах и содержит всю информацию, необходимую для выполнения любой запланированной задачи на этом агенте.

Весь этот процесс изображается следующим потоком:

./9f8022f9acb5aafb8dd74e8cb7bd9758.jpg

Сначала агенты сообщают о своих ресурсах мастеру. В этот момент мастер предлагает эти ресурсы всем зарегистрированным планировщикам. Этот процесс известен как предложение ресурса, и мы подробно обсудим его в следующем разделе.

Затем планировщик выбирает лучшего агента и выполняет на нем различные задачи через Мастера. Как только исполнитель завершает назначенную задачу, агенты повторно публикуют свои ресурсы мастеру. Мастер повторяет этот процесс совместного использования ресурсов для всех фреймворков в кластере.

Mesos позволяет приложениям реализовывать собственный планировщик и исполнитель на различных языках программирования. Java -реализация планировщика должна реализовывать интерфейс планировщика :

public class HelloWorldScheduler implements Scheduler {

@Override
public void registered(SchedulerDriver schedulerDriver, Protos.FrameworkID frameworkID,
Protos.MasterInfo masterInfo) {
}

@Override
public void reregistered(SchedulerDriver schedulerDriver, Protos.MasterInfo masterInfo) {
}

@Override
public void resourceOffers(SchedulerDriver schedulerDriver, List<Offer> list) {
}

@Override
public void offerRescinded(SchedulerDriver schedulerDriver, OfferID offerID) {
}

@Override
public void statusUpdate(SchedulerDriver schedulerDriver, Protos.TaskStatus taskStatus) {
}

@Override
public void frameworkMessage(SchedulerDriver schedulerDriver, Protos.ExecutorID executorID,
Protos.SlaveID slaveID, byte[] bytes) {
}

@Override
public void disconnected(SchedulerDriver schedulerDriver) {
}

@Override
public void slaveLost(SchedulerDriver schedulerDriver, Protos.SlaveID slaveID) {
}

@Override
public void executorLost(SchedulerDriver schedulerDriver, Protos.ExecutorID executorID,
Protos.SlaveID slaveID, int i) {
}

@Override
public void error(SchedulerDriver schedulerDriver, String s) {
}
}

Как видно, он в основном состоит из различных методов обратного вызова для связи, в частности, с мастером .

Точно так же реализация исполнителя должна реализовывать интерфейс Executor :

public class HelloWorldExecutor implements Executor {
@Override
public void registered(ExecutorDriver driver, Protos.ExecutorInfo executorInfo,
Protos.FrameworkInfo frameworkInfo, Protos.SlaveInfo slaveInfo) {
}

@Override
public void reregistered(ExecutorDriver driver, Protos.SlaveInfo slaveInfo) {
}

@Override
public void disconnected(ExecutorDriver driver) {
}

@Override
public void launchTask(ExecutorDriver driver, Protos.TaskInfo task) {
}

@Override
public void killTask(ExecutorDriver driver, Protos.TaskID taskId) {
}

@Override
public void frameworkMessage(ExecutorDriver driver, byte[] data) {
}

@Override
public void shutdown(ExecutorDriver driver) {
}
}

Мы увидим рабочую версию планировщика и исполнителя в следующем разделе.

4. Управление ресурсами

4.1. Предложения ресурсов

Как мы обсуждали ранее, агенты публикуют информацию о своих ресурсах мастеру. В свою очередь мастер предлагает эти ресурсы платформам, работающим в кластере. Этот процесс известен как предложение ресурса.

Предложение ресурсов состоит из двух частей – ресурсов и атрибутов.

Ресурсы используются для публикации информации об оборудовании машины агента, такой как память, ЦП и диск.

Для каждого агента есть пять предопределенных ресурсов:

  • Процессор
  • графический процессор
  • мем
  • диск
  • порты

Значения для этих ресурсов могут быть определены в одном из трех типов:

  • Скаляр - используется для представления числовой информации с использованием чисел с плавающей запятой, чтобы разрешить дробные значения, такие как 1,5 ГБ памяти.
  • Диапазон — используется для представления диапазона скалярных значений — например, диапазона портов.
  • Set — используется для представления нескольких текстовых значений .

По умолчанию агент Mesos пытается обнаружить эти ресурсы с компьютера.

Однако в некоторых ситуациях мы можем настроить пользовательские ресурсы на агенте. Значения для таких пользовательских ресурсов снова должны относиться к одному из типов, описанных выше.

Например, мы можем запустить нашего агента со следующими ресурсами:

--resources='cpus:24;gpus:2;mem:24576;disk:409600;ports:[21000-24000,30000-34000];bugs(debug_role):{a,b,c}'

Как видно, мы настроили агент с несколькими предопределенными ресурсами и одним настраиваемым ресурсом с именем bugs , который имеет заданный тип.

В дополнение к ресурсам агенты могут публиковать атрибуты ключ-значение для мастера. Эти атрибуты действуют как дополнительные метаданные для агента и помогают структурам в планировании решений.

Полезным примером может быть добавление агентов в разные стойки или зоны, а затем планирование различных задач в той же стойке или зоне для достижения локальности данных:

--attributes='rack:abc;zone:west;os:centos5;level:10;keys:[1000-1500]'

Подобно ресурсам, значения атрибутов могут быть скалярными, диапазонными или текстовыми.

4.2. Роли ресурсов

Многие современные операционные системы поддерживают несколько пользователей. Точно так же Mesos также поддерживает несколько пользователей в одном кластере. Эти пользователи известны как роли . Мы можем рассматривать каждую роль как потребителя ресурсов в кластере.

Благодаря этому агенты Mesos могут распределять ресурсы по разным ролям на основе разных стратегий распределения. Более того, фреймворки могут подписываться на эти роли внутри кластера и иметь детальный контроль над ресурсами в рамках разных ролей.

Например, рассмотрим кластер, в котором размещаются приложения, обслуживающие разных пользователей в организации. Таким образом, разделяя ресурсы на роли, каждое приложение может работать изолированно друг от друга.

Кроме того, платформы могут использовать эти роли для обеспечения локальности данных.

Например, предположим, что у нас есть два приложения в кластере с именами производитель и потребитель. Здесь производитель записывает данные в постоянный том, который впоследствии может прочитать потребитель . Мы можем оптимизировать потребительское приложение, поделившись объемом с производителем.

Поскольку Mesos позволяет нескольким приложениям подписываться на одну и ту же роль, мы можем связать постоянный том с ролью ресурса. Кроме того, платформы как для производителя , так и для потребителя будут подписываться на одну и ту же роль ресурса. Таким образом, приложение- потребитель теперь может запускать задачу чтения данных на том же томе , что и приложение- производитель .

4.3. Резервирование ресурсов

Теперь может возникнуть вопрос, как Mesos распределяет ресурсы кластера по разным ролям. Mesos распределяет ресурсы посредством резервирования.

Существует два типа резервирования:

  • Статическое резервирование
  • Динамическое резервирование

Статическое резервирование похоже на выделение ресурсов при запуске агента, которое мы обсуждали в предыдущих разделах:

--resources="cpus:4;mem:2048;cpus(foreach):8;mem(foreach):4096"

Единственная разница здесь в том, что теперь агент Mesos резервирует восемь процессоров и 4096 м памяти для роли с именем foreach .

Динамическое резервирование позволяет нам перетасовывать ресурсы внутри ролей, в отличие от статического резервирования. Mesos позволяет фреймворкам и операторам кластеров динамически изменять распределение ресурсов через сообщения фреймворка в ответ на предложение ресурсов или через конечные точки HTTP .

Mesos выделяет все ресурсы без какой-либо роли в роль по умолчанию с именем (*). Master предлагает такие ресурсы для всех фреймворков, независимо от того, подписаны они на него или нет.

4.4. Вес ресурсов и квоты

Как правило, мастер Mesos предлагает ресурсы, используя стратегию справедливости. Он использует взвешенную доминантную справедливость ресурсов (wDRF) для определения ролей, которым не хватает ресурсов. Затем мастер предлагает больше ресурсов платформам, подписавшимся на эти роли.

Несмотря на то, что справедливое распределение ресурсов между приложениями является важной характеристикой Mesos, оно не всегда необходимо. Предположим, в кластере размещаются приложения, которые требуют мало ресурсов, а также те, которые требуют больших ресурсов. В таких развертываниях мы хотели бы распределять ресурсы в зависимости от характера приложения.

Mesos позволяет фреймворкам требовать больше ресурсов, подписываясь на роли и добавляя более высокое значение веса для этой роли. Следовательно, если есть две роли, одна с весом 1, а другая с весом 2, Mesos выделит вдвое большую справедливую долю ресурсов для второй роли.

Как и в случае с ресурсами, мы можем настраивать веса через конечные точки HTTP .

Помимо обеспечения справедливой доли ресурсов для роли с весами, Mesos также гарантирует выделение минимальных ресурсов для роли.

Mesos позволяет нам добавлять квоты к ролям ресурсов. Квота определяет минимальное количество ресурсов, которое гарантированно получает роль .

5. Внедрение фреймворка

Как мы обсуждали в предыдущем разделе, Mesos позволяет приложениям предоставлять реализацию фреймворка на языке по своему выбору. В Java инфраструктура реализуется с использованием основного класса, который выступает в качестве точки входа для процесса фреймворка, и реализации Scheduler и Executor , обсуждавшихся ранее.

5.1. Основной класс фреймворка

Прежде чем мы реализуем планировщик и исполнитель, мы сначала реализуем точку входа для нашей структуры, которая:

  • Регистрирует себя у мастера
  • Предоставляет агентам информацию о времени выполнения исполнителя
  • Запускает планировщик

Сначала мы добавим зависимость Maven для Mesos:

<dependency>
<groupId>org.apache.mesos</groupId>
<artifactId>mesos</artifactId>
<version>0.28.3</version>
</dependency>

Далее мы реализуем HelloWorldMain для нашего фреймворка. Первое, что мы сделаем, это запустим процесс-исполнитель на агенте Mesos:

public static void main(String[] args) {

String path = System.getProperty("user.dir")
+ "/target/libraries2-1.0.0-SNAPSHOT.jar";

CommandInfo.URI uri = CommandInfo.URI.newBuilder().setValue(path).setExtract(false).build();

String helloWorldCommand = "java -cp libraries2-1.0.0-SNAPSHOT.jar com.foreach.mesos.executors.HelloWorldExecutor";
CommandInfo commandInfoHelloWorld = CommandInfo.newBuilder()
.setValue(helloWorldCommand)
.addUris(uri)
.build();

ExecutorInfo executorHelloWorld = ExecutorInfo.newBuilder()
.setExecutorId(Protos.ExecutorID.newBuilder()
.setValue("HelloWorldExecutor"))
.setCommand(commandInfoHelloWorld)
.setName("Hello World (Java)")
.setSource("java")
.build();
}

Здесь мы сначала настроили двоичное расположение исполнителя. Агент Mesos загружал этот бинарный файл при регистрации фреймворка. Затем агент выполнит данную команду, чтобы запустить процесс-исполнитель.

Далее мы инициализируем наш фреймворк и запустим планировщик:

FrameworkInfo.Builder frameworkBuilder = FrameworkInfo.newBuilder()
.setFailoverTimeout(120000)
.setUser("")
.setName("Hello World Framework (Java)");

frameworkBuilder.setPrincipal("test-framework-java");

MesosSchedulerDriver driver = new MesosSchedulerDriver(new HelloWorldScheduler(),
frameworkBuilder.build(), args[0]);

Наконец, мы запустим MesosSchedulerDriver , который зарегистрируется в Мастере. Для успешной регистрации мы должны передать IP Мастера в качестве аргумента программы args[0] этому основному классу:

int status = driver.run() == Protos.Status.DRIVER_STOPPED ? 0 : 1;

driver.stop();

System.exit(status);

В классе, показанном выше, CommandInfo, ExecutorInfo и FrameworkInfo являются Java-представлениями сообщений protobuf между мастером и платформами.

5.2. Реализация планировщика

Начиная с Mesos 1.0, мы можем вызывать конечную точку HTTP из любого Java-приложения для отправки и получения сообщений мастеру Mesos . Некоторые из этих сообщений включают, например, регистрацию платформы, предложения ресурсов и отклонения предложений.

Для Mesos 0.28 или более ранней версии нам необходимо реализовать интерфейс Планировщика :

По большей части мы сосредоточимся только на методе resourceOffers Планировщика. Давайте посмотрим, как планировщик получает ресурсы и инициализирует задачи на их основе.

Сначала посмотрим, как планировщик распределяет ресурсы для задачи:

@Override
public void resourceOffers(SchedulerDriver schedulerDriver, List<Offer> list) {

for (Offer offer : list) {
List<TaskInfo> tasks = new ArrayList<TaskInfo>();
Protos.TaskID taskId = Protos.TaskID.newBuilder()
.setValue(Integer.toString(launchedTasks++)).build();

System.out.println("Launching printHelloWorld " + taskId.getValue() + " Hello World Java");

Protos.Resource.Builder cpus = Protos.Resource.newBuilder()
.setName("cpus")
.setType(Protos.Value.Type.SCALAR)
.setScalar(Protos.Value.Scalar.newBuilder()
.setValue(1));

Protos.Resource.Builder mem = Protos.Resource.newBuilder()
.setName("mem")
.setType(Protos.Value.Type.SCALAR)
.setScalar(Protos.Value.Scalar.newBuilder()
.setValue(128));

Здесь мы выделили 1 ЦП и 128 МБ памяти для нашей задачи. Далее мы будем использовать SchedulerDriver для запуска задачи на агенте:

TaskInfo printHelloWorld = TaskInfo.newBuilder()
.setName("printHelloWorld " + taskId.getValue())
.setTaskId(taskId)
.setSlaveId(offer.getSlaveId())
.addResources(cpus)
.addResources(mem)
.setExecutor(ExecutorInfo.newBuilder(helloWorldExecutor))
.build();

List<OfferID> offerIDS = new ArrayList<>();
offerIDS.add(offer.getId());

tasks.add(printHelloWorld);

schedulerDriver.launchTasks(offerIDS, tasks);
}
}

Кроме того, планировщику часто приходится отклонять предложения ресурсов. Например, если планировщик не может запустить задачу на агенте из-за нехватки ресурсов, он должен немедленно отклонить это предложение:

schedulerDriver.declineOffer(offer.getId());

5.3. Реализующий исполнитель

Как мы обсуждали ранее, исполнительный компонент платформы отвечает за выполнение задач приложения в агенте Mesos.

Мы использовали конечные точки HTTP для реализации планировщика в Mesos 1.0. Точно так же мы можем использовать конечную точку HTTP для исполнителя.

В предыдущем разделе мы обсуждали, как фреймворк настраивает агента для запуска процесса-исполнителя:

java -cp libraries2-1.0.0-SNAPSHOT.jar com.foreach.mesos.executors.HelloWorldExecutor

Примечательно, что эта команда считает HelloWorldExecutor основным классом. Мы реализуем этот основной метод для инициализации MesosExecutorDriver , который соединяется с агентами Mesos для получения задач и обмена другой информацией, такой как статус задачи:

public class HelloWorldExecutor implements Executor {
public static void main(String[] args) {
MesosExecutorDriver driver = new MesosExecutorDriver(new HelloWorldExecutor());
System.exit(driver.run() == Protos.Status.DRIVER_STOPPED ? 0 : 1);
}
}

Последнее, что сейчас нужно сделать, это принять задачи от фреймворка и запустить их на агенте. Информация для запуска любой задачи содержится в HelloWorldExecutor:

public void launchTask(ExecutorDriver driver, TaskInfo task) {

Protos.TaskStatus status = Protos.TaskStatus.newBuilder()
.setTaskId(task.getTaskId())
.setState(Protos.TaskState.TASK_RUNNING)
.build();
driver.sendStatusUpdate(status);

System.out.println("Execute Task!!!");

status = Protos.TaskStatus.newBuilder()
.setTaskId(task.getTaskId())
.setState(Protos.TaskState.TASK_FINISHED)
.build();
driver.sendStatusUpdate(status);
}

Конечно, это всего лишь простая реализация, но она объясняет, как исполнитель делится статусом задачи с мастером на каждом этапе, а затем выполняет задачу перед отправкой статуса завершения.

В некоторых случаях исполнители также могут отправлять данные обратно планировщику:

String myStatus = "Hello Framework";
driver.sendFrameworkMessage(myStatus.getBytes());

6. Заключение

В этой статье мы кратко обсудили совместное использование ресурсов между приложениями, работающими в одном кластере. Мы также обсудили, как Apache Mesos помогает приложениям достичь максимального использования с абстрактным представлением ресурсов кластера, таких как ЦП и память.

Позже мы обсудили динамическое распределение ресурсов между приложениями на основе различных политик и ролей справедливости. Mesos позволяет приложениям принимать решения о планировании на основе предложений ресурсов от агентов Mesos в кластере.

Наконец, мы увидели реализацию фреймворка Mesos на Java.

Как обычно, все примеры доступны на GitHub .