Статьи

Создание масштабируемых распределенных систем с использованием Go и Mesos

Apache Mesos — это менеджер ресурсов и планировщик, который работает как системное ядро ​​для центра обработки данных. Он отводит ресурсы ЦП, памяти, хранилища и других вычислительных ресурсов от машин (физических или виртуальных), что позволяет легко создавать и эффективно работать отказоустойчивые и эластичные распределенные системы. Например, оригинальная версия Apache Spark была построена поверх Mesos, когда оба проекта были частью AMPLab в Калифорнийском университете в Беркли.

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

На старт, внимание, марш!

Apache Mesos использует идиому, известную как платформа, для делегирования планирования задач клиентскому коду, работающему в кластере. Например, Spark изначально был средой Mesos, написанной для API Mesos с использованием привязок языка Scala.

Оригинальная версия Mesos была построена в 2009 году, до того, как Go был популярен. Сегодня Go является одним из самых популярных языков, и многие ключевые компоненты, которые интегрируются с Mesos, написаны на Go. Например, Kubernetes-Mesos , среда Mesos для запуска рабочих нагрузок Kubernetes на Mesos, написана на Go. Кроме того, Go пользуется популярностью среди многих инструментов инфраструктуры, включая и окружающий формат контейнера Docker, который изначально поддерживается Mesos .

Теперь стало возможным создавать каркасы Mesos в Go, используя привязки к чистому языку Go. Эта возможность позволит сообществу Go создавать совершенно новое поколение распределенных систем. В оставшейся части этой статьи будет объяснено, как работают новые привязки Go в Mesos, и будет показано, как построить новую среду распределенных систем на Mesos с использованием Go.

Привязки Mesos Framework

До версии 0.19.0 Apache Mesos (выпущенной в июне 2014 г.) у программиста, который хотел реализовать инфраструктуру Mesos, был только один вариант взаимодействия с API Mesos — главным образом, с использованием предоставленной библиотеки libmesos.so C / C ++. modulue. Это привело к нескольким языковым привязкам, которые сильно зависят от кода libmesos для работы, включая:

  • Java / Scala
  • питон
  • Perl
  • Haskell
  • Идти

Хотя использование внешнего модуля C / C ++ для этих привязок работает нормально, они имеют некоторые обременительные побочные эффекты:

  • выбранный язык должен иметь способ взаимодействия с C / C ++
  • между языком хоста и API C / C ++ существуют идиоматические пробелы
  • существует потребность в уровне абстракции для смягчения проблем четности представления данных
  • существует зависимость времени сборки (для скомпилированных языков) от libmesos.so
  • libmesos.so должен распространяться с кодом для удовлетворения зависимостей во время выполнения

Прямая привязка протокола

Начиная с версии 0.19.0, сообщество Apache Mesos представило изменения в проводном протоколе Mesos на основе HTTP, которые позволили разработчикам создавать интегрированные среды, напрямую связанные с базовым стеком HTTP, предоставляемым языком. Это открыло перед программистами возможность создавать фреймворки Mesos исключительно на языке по своему выбору без внешней зависимости от кода C / C ++.

После выпуска версии 0.19 было реализовано несколько проектов, в которых API-интерфейс Mesos реализован непосредственно на их родном языке, в том числе:

• Jesos, Java-реализация — https://github.com/groupon/jesos
• Pesos, Python-реализация Python — https://github.com/wickman/pesos
• Mesos-Go, реализация Go (см. Ниже)

Остальная часть этой статьи посвящена Mesos-Go, чистой реализации Go библиотеки фреймворков Apache-Mesos.

Mesos-Go — Github.com/mesos/mesos-go

Mesos-Go — это чистая реализация API-интерфейса Apache Mesos, написанная на языке программирования Go ( http://golang.org ). Как указывалось ранее, оригинальный проект Mesos-Go использовал привязку C / C ++ в своей предыдущей жизни. Однако в своем последнем реинкарнации Mesos-Go полностью написан на Go и не зависит от библиотечного модуля libmesos.so C / C ++. Проект использует протокол HTTP для прямой связи с работающим мастером Mesos и / или его подчиненными экземплярами.

Начало работы с Mesos-Go

Этот раздел статьи посвящен использованию привязок Mesos-Go для создания клиентских платформ в Go. Он предоставляет общий обзор API и необходимые примеры кода, которые показывают, как написать простой планировщик Mesos .

Предпосылки

Создание Кодекса

В командной строке выполните следующие действия:

$ cd $GOPATH/src/$ mkdir -p github.com/mesos/mesos-go$ git clone https://github.com/mesos/mesos-go.git github.com/mesos/mesos-go$ cd github.com/mesos/mesos-go$ godep restore
$ go install ./...

Разработка платформ Mesos в Go

Mesos-Go предоставляет простой интерфейс приложения, который выровнен с C ++ API, чтобы максимизировать понятность и переносимость. В следующих разделах мы рассмотрим, как использовать API для создания простого примера среды Mesos, находящейся в каталоге examples / исходного кода. Инструкции по сборке Mesos-Go и сопровождающие примеры см. По адресу https://github.com/mesos/mesos-go

Если вы не знакомы с тем, как работает Mesos, сейчас самое время ознакомиться с документацией Mesos http://mesos.apache.org/documentation/latest/ и ее архитектурой http://mesos.apache.org/documentation. / последняя / мезос-архитектура / .

Пакеты Mesos-Go

Когда вы будете готовы использовать API, вы в первую очередь будете взаимодействовать со следующими высокоуровневыми пакетами:

Написание планировщика

Создание планировщика платформы включает в себя два компонента: планировщик и планировщик . Все платформы Mesos должны реализовывать  интерфейс S cheduler, который, в свою очередь, использует   модуль SchedulerDriver для обработки связи с мастером Mesos. Давайте подробнее рассмотрим два компонента.

Интерфейс Планировщика

Разработчик фреймворка должен начать с реализации интерфейса Mesos  Scheduler в Go. Планировщик  , где разработчик будет размещать код:

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

Ниже приведено полное определение интерфейса планировщика. SchedulerDriver (покрыто далее) использует механизм обратного вызова для делегирования Mesos обработки событий к соответствующему методу планировщика , как указаны в определении типа ниже (л чернил к планировщику интерфейса документации: https://godoc.org/github.com/mesos / mesos-go / scheduler # Scheduler ) .

type Scheduler interface {
    Registered(SchedulerDriver, *mesos.FrameworkID, *mesos.MasterInfo)
    Reregistered(SchedulerDriver, *mesos.MasterInfo)
    Disconnected(SchedulerDriver)
    ResourceOffers(SchedulerDriver, []*mesos.Offer)
    OfferRescinded(SchedulerDriver, *mesos.OfferID)
    StatusUpdate(SchedulerDriver, *mesos.TaskStatus)
    FrameworkMessage(SchedulerDriver, 
        *mesos.ExecutorID, *mesos.SlaveID, string)
    SlaveLost(SchedulerDriver, *mesos.SlaveID)
    ExecutorLost(SchedulerDriver, *mesos.ExecutorID, *mesos.SlaveID, int)
    Error(SchedulerDriver, string)
}

Планировщик Драйвер

SchedulerDriver представляет собой модуль обеспечивает Mesos-Go , которая предназначена для обработки связи между каркасом и мастером Mesos. Он предоставляет свои услуги несколькими способами:

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

Чтобы начать работу с драйвером, разработчику каркаса потребуется создать новый экземпляр SchedulerDriver, используя следующую функцию конструктора, найденную в пакете планировщика .

scheduler.NewMesosSchedulerDriver(
    sched Scheduler,                 // Scheduler instance
    framework *mesos.FrameworkInfo,  // Framework information
    master string,                   // Mesos master address
    credential *mesos.Credential,    // Credential 
) (*MesosSchedulerDriver, error)         // Returns a pointer to driver or error

Функция конструктора создает новый экземпляр SchedulerDriver или возвращает ошибку, если что-то пошло не так. Обратите внимание, что вы должны предоставить экземпляр планировщика вашей платформы (рассмотренный ранее) в качестве параметра для вызова функции. Это как указать, какую реализацию планировщика использовать для платформы. Пример кода в следующем разделе показывает рабочий процесс создания полностью работающего примера структуры.

Ссылка на документацию SchedulerDriver —  https://godoc.org/github.com/mesos/mesos-go/scheduler#SchedulerDriver.

Пример планировщика

Следующий фрагмент кода взят из examples / test_framework.go ( https://github.com/mesos/mesos-go/blob/master/examples/test_framework.go . Сокращенный код, приведенный ниже, показывает реализацию простой среды Mesos ( но подробности см. в оригинале) (сокращенно). Первая часть кода реализует интерфейс планировщика (опять же, показаны не все реализованные методы).

type ExampleScheduler struct {
executor      *mesos.ExecutorInfo
tasksLaunched int
tasksFinished int
totalTasks    int
}

func (sched *ExampleScheduler) Registered(
driver sched.SchedulerDriver, 
frameworkId *mesos.FrameworkID, 
masterInfo *mesos.MasterInfo) {...}
...
func (sched *ExampleScheduler) ResourceOffers(
driver sched.SchedulerDriver, offers []*mesos.Offer) { ... }
...
func (sched *ExampleScheduler) Error(
driver sched.SchedulerDriver, err string){...}

В оставшейся части примера кода показано создание нового экземпляра SchedulerDriver и запуск инфраструктуры:

func main() {
// the command to be executed by slave processes
exec := &mesos.ExecutorInfo{
ExecutorId: util.NewExecutorID("default"),
Name:       proto.String("Test Executor (Go)"),
Source:     proto.String("go_test"),
Command:    util.NewCommandInfo("/tmp/test-executor"),
}

// the framework info
fwinfo := &mesos.FrameworkInfo{
User: proto.String(""), // Mesos-go will fill in user.
Name: proto.String("Test Framework (Go)"),
}

//create the SchedulerDriver instance
     driver, err := scheduler.NewMesosSchedulerDriver(
newExampleScheduler(exec),
fwinfo,
"127.0.0.1:5050",
nil,
)
if stat, err := driver.Run(); err != nil {
    log.Infof("Framework stopped... %s and error: %s\n",
    stat.String(), err.Error())
}
}

Переменные exec и fwinfo хранят объекты буфера протокола, необходимые для описания исполнителя, который будет запущен, и описания структуры, которая будет зарегистрирована соответственно. Как только SchedulerDriver создан, он используется для запуска и регистрации фреймворка в Mesos master с помощью метода driver.Run (), который будет блокироваться до тех пор, пока не будет вызван driver.Stop () .

Написание исполнителя

Вторая половина написания платформы Mesos — это реализация исполнителя,  который определяет распределенную задачу, которая должна выполняться подчиненными узлами в кластере. Как и в планировщике, создание исполнителя executor требует двух компонентов:  интерфейса Executor и ExecutorDriver . Исполнитель — это фрагмент кода, который фактически выполняется на подчиненных узлах в кластере Mesos для выполнения полезной работы. Executor, в свою очередь, использует ExecutorDriver для обработки связи с подчиненными Mesos. Давайте подробнее рассмотрим эти компоненты.

Интерфейс исполнителя

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

  • запускать и запускать задачи (или задачи), запрошенные планировщиком инфраструктуры
  • Отключение ручки от работающего раба
  • получать сообщения из фреймворка
  • обработать запрос, чтобы убить запущенную задачу
  • И т.п.

Ниже приведено полное определение интерфейса Executor (ссылка на документацию — https://godoc.org/github.com/mesos/mesos-go/executor#Executor).  

type Executor interface {
Registered(ExecutorDriver, *mesosproto.ExecutorInfo, 
*mesosproto.FrameworkInfo, *mesosproto.SlaveInfo)
Reregistered(ExecutorDriver, *mesosproto.SlaveInfo)
Disconnected(ExecutorDriver)
LaunchTask(ExecutorDriver, *mesosproto.TaskInfo)
KillTask(ExecutorDriver, *mesosproto.TaskID)
FrameworkMessage(ExecutorDriver, string)
Shutdown(ExecutorDriver)
Error(ExecutorDriver, string)
}

Основным методом Исполнителя является его LaunchTask () . Он вызывается, когда связанный планировщик запрашивает запуск задачи в кластере. Реализация задачи зависит от спецификации каркаса. Он может просто запускать процесс ОС, запускать новые потоки или выполнять простые вычисления.

Драйвер исполнителя

ExecutorDriver  осуществляется Mesos-Go и ручками взаимодействия между рамочным исполнителем и подчиненного узла , выполняющего задачу. У драйвера несколько методов, в том числе возможность  отправлять обновления статуса в связанный планировщик и связываться с планировщиком путем отправки произвольных сообщений.  Чтобы создать драйвер executor, используйте следующую функцию конструктора, найденную в пакете executor .

executor.NewMesosExecutorDriver(exec Executor) (*MesosExecutorDriver, error)

Функция конструктора драйвера вернет новый экземпляр MesosExecutorDriver или ошибку, если что-то пойдет не так. Обратите внимание, что вы должны предоставить экземпляр исполнителя вашей платформы в качестве параметра для вызова функции. Это позволяет вам указать реализацию Executor, которая будет выполнять данную задачу всякий раз, когда драйвер получает запрос на запуск задачи. Пример кода в следующем разделе показывает рабочий процесс для создания полностью работающего примера исполнителя.

Образец Исполнителя

Следующий фрагмент кода — из examples / test_executor.go ( https://github.com/mesos/mesos-go/blob/master/examples/test_executor.go ) — показывает сокращенный пример исполнителя. Первая часть кода показывает реализацию интерфейса Executor.

// Type for implementing Executor
type exampleExecutor struct {
tasksLaunched int
}
func (exec *exampleExecutor) Registered(
driver exec.ExecutorDriver, 
execInfo *mesos.ExecutorInfo,
fwinfo *mesos.FrameworkInfo, 
slaveInfo *mesos.SlaveInfo) {...}

func (exec *exampleExecutor) LaunchTask(
driver exec.ExecutorDriver, taskInfo *mesos.TaskInfo) {...}
...
func (exec *exampleExecutor) Error(
driver exec.ExecutorDriver, err string) {...}

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

func main(){
driver, err := exec.NewMesosExecutorDriver(newExampleExecutor())
if err != nil {
fmt.Println("Unable to create a ExecutorDriver ", err.Error())
}
if stat, err := driver.Run(); err != nil {
    log.Infof("Executor stopped %s and error: %s\n", 
    stat.String(), err.Error())
}
}

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

Попробуй!

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

Ссылки