Apache Mesos 가이드

1. 개요

일반적으로 동일한 머신 클러스터에 다양한 애플리케이션을 배포합니다. 예를 들어, 오늘날 동일한 클러스터에 Apache Cassandra와 같은 분산 데이터베이스가있는 Apache Spark 또는 Apache Flink와 같은 분산 처리 엔진이있는 것이 일반적입니다.

Apache Mesos는 이러한 애플리케이션간에 효과적인 리소스 공유를 허용하는 플랫폼입니다.

이 기사에서는 먼저 동일한 클러스터에 배포 된 애플리케이션 내 리소스 할당의 몇 가지 문제에 대해 설명합니다. 나중에 Apache Mesos가 애플리케이션간에 더 나은 리소스 활용을 제공하는 방법을 살펴 보겠습니다.

2. 클러스터 공유

많은 애플리케이션이 클러스터를 공유해야합니다. 대체로 두 가지 일반적인 접근 방식이 있습니다.

  • 클러스터를 정적으로 분할하고 각 파티션에서 애플리케이션을 실행합니다.
  • 애플리케이션에 머신 세트 할당

이러한 접근 방식을 사용하면 응용 프로그램이 서로 독립적으로 실행될 수 있지만 리소스 사용률이 높지 않습니다.

예를 들어 짧은 기간 동안 만 실행되고 비활성 기간이 뒤 따르는 응용 프로그램을 생각해보십시오 . 이제이 애플리케이션에 정적 머신 또는 파티션을 할당 했으므로 비활성 기간 동안 사용되지 않은 리소스 가 있습니다 .

비활성 기간 동안 사용 가능한 리소스를 다른 애플리케이션에 재 할당하여 리소스 활용도를 최적화 할 수 있습니다.

Apache Mesos는 애플리케이션 간의 동적 리소스 할당을 지원합니다.

3. Apache Mesos

위에서 논의한 두 가지 클러스터 공유 접근 방식을 사용하면 응용 프로그램은 실행중인 특정 파티션 또는 시스템의 리소스 만 인식합니다. 그러나 Apache Mesos는 클러스터의 모든 리소스에 대한 추상보기를 애플리케이션에 제공합니다.

곧 살펴 보 겠지만 Mesos는 기계와 응용 프로그램 간의 인터페이스 역할을합니다. 클러스터의 모든 시스템에서 사용 가능한 리소스를 응용 프로그램에 제공 합니다. 그것은 자주 응용 프로그램에 의해 해제되는 자원을 포함하려면이 정보 업데이트 완료 상태에 도달했습니다. 이를 통해 응용 프로그램은 어떤 컴퓨터에서 어떤 작업을 실행할지에 대해 최상의 결정을 내릴 수 있습니다.

Mesos의 작동 방식을 이해하기 위해 아키텍처를 살펴 보겠습니다.

이 이미지는 Mesos에 대한 공식 문서의 일부입니다 (소스). 여기서 HadoopMPI 는 클러스터를 공유하는 두 가지 애플리케이션입니다.

다음 몇 섹션에서 여기에 표시된 각 구성 요소에 대해 설명합니다.

3.1. 메 소스 마스터

마스터는이 설정의 핵심 구성 요소이며 클러스터에 현재 리소스 상태를 저장합니다. 또한 리소스 및 작업과 같은 정보를 전달 하여 에이전트 와 응용 프로그램 간의 조정자 역할을 합니다.

마스터에서 오류가 발생하면 리소스 및 작업에 대한 상태가 손실되므로 고 가용성 구성으로 배포합니다. 위의 다이어그램에서 볼 수 있듯이 Mesos는 하나의 리더와 함께 대기 마스터 데몬을 배포합니다. 이러한 데몬은 장애 발생시 상태를 복구하기 위해 Zookeeper에 의존합니다.

3.2. Mesos 에이전트

Mesos 클러스터는 모든 시스템에서 에이전트를 실행해야합니다. 이러한 에이전트 는 주기적으로 리소스를 마스터에보고하고 차례로 애플리케이션이 실행하도록 예약 한 작업을받습니다 . 이주기는 예약 된 작업이 완료되거나 손실 된 후에 반복됩니다.

다음 섹션에서는 애플리케이션이 이러한 에이전트에서 작업을 예약하고 실행하는 방법을 살펴 보겠습니다.

3.3. Mesos 프레임 워크

메소는 응용 프로그램이 마스터와 상호 작용을 할 수 있다는 추상적 인 구성 요소를 구현할 수 있습니다 사용할 수있는 클러스터의 자원을 수신 하고 또한 메이크업 스케줄링 결정 들을 기반으로합니다. 이러한 구성 요소를 프레임 워크라고합니다.

Mesos 프레임 워크는 두 개의 하위 구성 요소로 구성됩니다.

  • 스케줄러 – 애플리케이션이 모든 에이전트에서 사용 가능한 리소스를 기반으로 작업을 예약 할 수 있습니다.
  • 실행자 – 모든 에이전트에서 실행되며 해당 에이전트에서 예약 된 작업을 실행하는 데 필요한 모든 정보를 포함합니다.

이 전체 프로세스는 다음 흐름으로 설명됩니다.

먼저 에이전트는 자신의 자원을 마스터에게보고합니다. 이때 master는 등록 된 모든 스케줄러에 이러한 리소스를 제공합니다. 이 프로세스를 리소스 제안이라고하며 다음 섹션에서 자세히 설명합니다.

그런 다음 스케줄러는 최상의 에이전트를 선택하고 마스터를 통해 다양한 작업을 실행합니다. 실행자가 할당 된 작업을 완료하자마자 상담원은 자신의 리소스를 마스터에 다시 게시합니다. 마스터는 클러스터의 모든 프레임 워크에 대해이 리소스 공유 프로세스를 반복합니다.

Mesos를 사용하면 응용 프로그램이 다양한 프로그래밍 언어로 맞춤형 스케줄러 및 실행기구현할 수 있습니다. 스케줄러의 자바 구현해야한다 구현 스케줄러 인터페이스를 :

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 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. 리소스 제공

앞서 논의했듯이 에이전트는 자신의 리소스 정보를 마스터에 게시합니다. 차례로 마스터는 이러한 리소스를 클러스터에서 실행되는 프레임 워크에 제공합니다. 이 프로세스를 리소스 제공 이라고 합니다.

자원 제안은 자원과 속성의 두 부분으로 구성됩니다.

리소스는 메모리, CPU 및 디스크와 같은 에이전트 시스템의 하드웨어 정보게시 하는 데 사용됩니다 .

모든 에이전트에 대해 사전 정의 된 5 개의 리소스가 있습니다.

  • CPU
  • GPU
  • mem
  • 디스크
  • 포트

이러한 리소스의 값은 다음 세 가지 유형 중 하나로 정의 할 수 있습니다.

  • 스칼라 – 1.5G 메모리와 같은 분수 값을 허용하기 위해 부동 소수점 숫자를 사용하여 숫자 정보를 나타내는 데 사용됩니다.
  • 범위 – 스칼라 값 범위를 나타내는 데 사용됩니다 (예 : 포트 범위).
  • Set – Used to represent multiple text values

By default, Mesos agent tries to detect these resources from the machine.

However, in some situations, we can configure custom resources on an agent. The values for such custom resources should again be in any one of the types discussed above.

For instance, we can start our agent with these resources:

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

As can be seen, we've configured the agent with few of the predefined resources and one custom resource named bugs which is of set type.

In addition to resources, agents can publish key-value attributes to the master. These attributes act as additional metadata for the agent and help frameworks in scheduling decisions.

A useful example can be to add agents into different racks or zones and then schedule various tasks on the same rack or zone to achieve data locality:

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

Similar to resources, values for attributes can be either a scalar, a range, or a text type.

4.2. Resource Roles

Many modern-day operating systems support multiple users. Similarly, Mesos also supports multiple users in the same cluster. These users are known as roles. We can consider each role as a resource consumer within a cluster.

Due to this, Mesos agents can partition the resources under different roles based on different allocation strategies. Furthermore, frameworks can subscribe to these roles within the cluster and have fine-grained control over resources under different roles.

For example, consider a cluster hosting applications which are serving different users in an organization. So by dividing the resources into roles, every application can work in isolation from one another.

Additionally, frameworks can use these roles to achieve data locality.

For instance, suppose we have two applications in the cluster named producer and consumer. Here, producer writes data to a persistent volume which consumer can read afterward. We can optimize the consumer application by sharing the volume with the producer.

Since Mesos allows multiple applications to subscribe to the same role, we can associate the persistent volume with a resource role. Furthermore, the frameworks for both producer and consumer will both subscribe to the same resource role. Therefore, the consumer application can now launch the data reading task on the same volume as the producer application.

4.3. Resource Reservation

Now the question may arise as to how Mesos allocates cluster resources into different roles. Mesos allocates the resources through reservations.

There are two types of reservations:

  • Static Reservation
  • Dynamic Reservation

Static reservation is similar to the resource allocation on agent startup we discussed in the earlier sections:

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

The only difference here is that now the Mesos agent reserves eight CPUs and 4096m of memory for the role named baeldung.

Dynamic reservation allows us to reshuffle the resources within roles, unlike the static reservation. Mesos allows frameworks and cluster operators to dynamically change the allocation of resources via framework messages as a response to resource offer or via HTTP endpoints.

Mesos allocates all resources without any role into a default role named (*). Master offers such resources to all frameworks whether or not they have subscribed to it.

4.4. Resource Weights and Quotas

Generally, the Mesos master offers resources using a fairness strategy. It uses the weighted Dominant Resource Fairness (wDRF) to identify the roles that lack resources. The master then offers more resources to the frameworks that have subscribed to these roles.

Event though fair sharing of resources between applications is an important characteristic of Mesos, its not always necessary. Suppose a cluster hosting applications that have a low resource footprint along with those having a high resource demand. In such deployments, we would want to allocate resources based on the nature of the application.

Mesos allows frameworks to demand more resources by subscribing to roles and adding a higher value of weight for that role. Therefore, if there are two roles, one of weight 1 and another of weight 2, Mesos will allocate twice the fair share of resources to the second role.

Similar to resources, we can configure weights via HTTP endpoints.

Besides ensuring a fair share of resources to a role with weights, Mesos also ensures that the minimum resources for a role are allocated.

Mesos allows us to add quotas to the resource roles. A quota specifies the minimum amount of resources that a role is guaranteed to receive.

5. Implementing Framework

As we discussed in an earlier section, Mesos allows applications to provide framework implementations in a language of their choice. In Java, a framework is implemented using the main class – which acts as an entry point for the framework process – and the implementation of Scheduler and Executor discussed earlier.

5.1. Framework Main Class

Before we implement a scheduler and an executor, we'll first implement the entry point for our framework that:

  • Registers itself with the master
  • Provides executor runtime information to agents
  • Starts the scheduler

We'll first add a Maven dependency for Mesos:

 org.apache.mesos mesos 0.28.3 

Next, we'll implement the HelloWorldMain for our framework. One of the first things we'll do is to start the executor process on the Mesos agent:

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.baeldung.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(); }

Here, we first configured the executor binary location. Mesos agent would download this binary upon framework registration. Next, the agent would run the given command to start the executor process.

Next, we'll initialize our framework and start the scheduler:

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]);

Finally, we'll start the MesosSchedulerDriver that registers itself with the Master. For successful registration, we must pass the IP of the Master as a program argument args[0] to this main class:

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

In the class shown above, CommandInfo, ExecutorInfo, and FrameworkInfo are all Java representations of protobuf messages between master and frameworks.

5.2. Implementing Scheduler

Since Mesos 1.0, we can invoke the HTTP endpoint from any Java application to send and receive messages to the Mesos master. Some of these messages include, for example, framework registration, resource offers, and offer rejections.

For Mesos 0.28 or earlier, we need to implement the Scheduler interface:

For the most part, we'll only focus on the resourceOffers method of the Scheduler. Let's see how a scheduler receives resources and initializes tasks based on them.

First, we'll see how the scheduler allocates resources for a task:

@Override public void resourceOffers(SchedulerDriver schedulerDriver, List list) { for (Offer offer : list) { List tasks = new ArrayList(); 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));

Here, we allocated 1 CPU and 128M of memory for our task. Next, we'll use the SchedulerDriver to launch the task on an agent:

 TaskInfo printHelloWorld = TaskInfo.newBuilder() .setName("printHelloWorld " + taskId.getValue()) .setTaskId(taskId) .setSlaveId(offer.getSlaveId()) .addResources(cpus) .addResources(mem) .setExecutor(ExecutorInfo.newBuilder(helloWorldExecutor)) .build(); List offerIDS = new ArrayList(); offerIDS.add(offer.getId()); tasks.add(printHelloWorld); schedulerDriver.launchTasks(offerIDS, tasks); } }

Alternatively, Scheduler often finds the need to reject resource offers. For example, if the Scheduler cannot launch a task on an agent due to lack of resources, it must immediately decline that offer:

schedulerDriver.declineOffer(offer.getId());

5.3. Implementing Executor

As we discussed earlier, the executor component of the framework is responsible for executing application tasks on the Mesos agent.

We used the HTTP endpoints for implementing Scheduler in Mesos 1.0. Likewise, we can use the HTTP endpoint for the executor.

In an earlier section, we discussed how a framework configures an agent to start the executor process:

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

Notably, this command considers HelloWorldExecutor as the main class. We'll implement this main method to initialize the MesosExecutorDriver that connects with Mesos agents to receive tasks and share other information like task status:

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); } }

The last thing to do now is to accept tasks from the framework and launch them on the agent. The information to launch any task is self-contained within the 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); }

Of course, this is just a simple implementation, but it explains how an executor shares task status with the master at every stage and then executes the task before sending a completion status.

In some cases, executors can also send data back to the scheduler:

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

6. Conclusion

이 기사에서는 동일한 클러스터에서 실행되는 애플리케이션 간의 리소스 공유에 대해 간략하게 설명했습니다. 또한 Apache Mesos가 CPU 및 메모리와 같은 클러스터 리소스에 대한 추상적 인보기를 통해 애플리케이션이 최대 활용도를 달성하도록 돕는 방법에 대해서도 논의했습니다.

나중에 다양한 공정성 정책과 역할 에 기반한 애플리케이션 간의 리소스 동적 할당에 대해 논의 했습니다. Mesos를 사용하면 응용 프로그램 이 클러스터의 Mesos 에이전트에서 제공하는 리소스를 기반으로 일정을 결정할 수 있습니다.

마지막으로 Java에서 Mesos 프레임 워크의 구현을 보았습니다.

평소처럼 모든 예제는 GitHub에서 사용할 수 있습니다.