Panduan untuk Apache Mesos

1. Gambaran keseluruhan

Kami biasanya menggunakan pelbagai aplikasi pada kelompok mesin yang sama. Sebagai contoh, biasa sekarang ini mempunyai mesin pemprosesan yang diedarkan seperti Apache Spark atau Apache Flink dengan pangkalan data yang diedarkan seperti Apache Cassandra dalam kluster yang sama.

Apache Mesos adalah platform yang membolehkan perkongsian sumber yang berkesan antara aplikasi tersebut.

Dalam artikel ini, pertama-tama kita akan membincangkan beberapa masalah peruntukan sumber dalam aplikasi yang digunakan pada kluster yang sama. Kemudian, kita akan melihat bagaimana Apache Mesos menyediakan penggunaan sumber yang lebih baik antara aplikasi.

2. Berkongsi Kluster

Banyak aplikasi perlu berkongsi kluster. Pada umumnya, terdapat dua pendekatan umum:

  • Bahagikan kluster secara statik dan jalankan aplikasi pada setiap partisi
  • Peruntukkan satu set mesin ke aplikasi

Walaupun pendekatan ini membolehkan aplikasi berjalan secara bebas antara satu sama lain, ia tidak mencapai penggunaan sumber yang tinggi.

Sebagai contoh, pertimbangkan aplikasi yang berjalan hanya untuk jangka waktu pendek diikuti dengan tempoh tidak aktif. Sekarang, kerana kami telah memperuntukkan mesin atau partisi statik untuk aplikasi ini, kami mempunyai sumber yang tidak digunakan dalam tempoh tidak aktif.

Kami dapat mengoptimumkan penggunaan sumber dengan mengalokasikan semula sumber percuma selama tempoh tidak aktif ke aplikasi lain.

Apache Mesos membantu dengan peruntukan sumber yang dinamik antara aplikasi.

3. Mesos Apache

Dengan kedua-dua pendekatan perkongsian kluster yang telah kita bincangkan di atas, aplikasi hanya mengetahui sumber partisi atau mesin tertentu yang mereka jalankan. Walau bagaimanapun, Apache Mesos memberikan pandangan abstrak dari semua sumber dalam kluster untuk aplikasi.

Seperti yang akan kita lihat sebentar lagi, Mesos bertindak sebagai antara muka antara mesin dan aplikasi. Ini menyediakan aplikasi dengan sumber daya yang tersedia pada semua mesin di kluster. Ia kerap mengemas kini maklumat ini untuk memasukkan sumber-sumber yang dibebaskan oleh aplikasi yang telah mencapai status siap. Ini membolehkan aplikasi membuat keputusan terbaik mengenai tugas yang harus dilaksanakan pada mesin mana.

Untuk memahami bagaimana Mesos berfungsi, mari kita lihat senibina:

Gambar ini adalah sebahagian daripada dokumentasi rasmi untuk Mesos (sumber). Di sini, Hadoop dan MPI adalah dua aplikasi yang berkongsi kluster.

Kami akan membincangkan setiap komponen yang ditunjukkan di sini dalam beberapa bahagian seterusnya.

3.1. Tuan Mesos

Master adalah komponen teras dalam penyediaan ini dan menyimpan keadaan sumber semasa dalam kluster. Selain itu, ia bertindak sebagai orkestrator antara ejen dan aplikasi dengan menyampaikan maklumat mengenai perkara seperti sumber dan tugas.

Oleh kerana sebarang kegagalan dalam master menyebabkan hilangnya keadaan mengenai sumber dan tugas, kami menyebarkannya dalam konfigurasi ketersediaan tinggi. Seperti yang dapat dilihat dalam rajah di atas, Mesos menggunakan daemon master siap sedia bersama dengan seorang pemimpin. Daemon ini bergantung pada Zookeeper untuk memulihkan keadaan sekiranya berlaku kegagalan.

3.2. Ejen Mesos

Sekumpulan Mesos mesti menjalankan ejen pada setiap mesin. Ejen ini melaporkan sumber mereka kepada tuan secara berkala dan seterusnya, menerima tugas yang telah dijadualkan oleh aplikasi untuk dijalankan . Kitaran ini berulang setelah tugas yang dijadualkan selesai atau hilang.

Kami akan melihat bagaimana aplikasi menjadualkan dan melaksanakan tugas pada ejen ini di bahagian berikut.

3.3. Kerangka Mesos

Mesos membolehkan aplikasi menerapkan komponen abstrak yang berinteraksi dengan Master untuk menerima sumber yang ada dalam kluster dan lebih-lebih lagi membuat keputusan penjadualan berdasarkannya. Komponen-komponen ini dikenali sebagai kerangka kerja.

Rangka kerja Mesos terdiri daripada dua sub-komponen:

  • Penjadual - Membolehkan aplikasi menjadualkan tugas berdasarkan sumber yang ada pada semua ejen
  • Executor - Berjalan pada semua ejen dan mengandungi semua maklumat yang diperlukan untuk melaksanakan tugas berjadual pada ejen tersebut

Seluruh proses ini digambarkan dengan aliran ini:

Pertama, ejen melaporkan sumber mereka kepada tuan. Pada masa ini, master menawarkan sumber-sumber ini kepada semua penjadual berdaftar. Proses ini dikenali sebagai tawaran sumber, dan kami akan membincangkannya secara terperinci di bahagian seterusnya.

Penjadual kemudian memilih ejen terbaik dan melaksanakan pelbagai tugas melalui Master. Sebaik sahaja pelaksana menyelesaikan tugas yang diberikan, ejen menerbitkan semula sumbernya kepada tuan. Master mengulangi proses perkongsian sumber ini untuk semua kerangka kerja dalam kluster.

Mesos membolehkan aplikasi melaksanakan penjadual dan pelaksana tersuai mereka dalam pelbagai bahasa pengaturcaraan. Pelaksanaan A Java penjadual perlu melaksanakan yang Scheduler muka :

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

Seperti yang dapat dilihat, kebanyakannya terdiri daripada pelbagai kaedah panggilan balik untuk komunikasi dengan tuan khususnya.

Begitu juga, pelaksanaan pelaksana mesti melaksanakan antara muka Pelaksana :

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

Kami akan melihat versi operasi penjadual dan pelaksana di bahagian kemudian.

4. Pengurusan Sumber

4.1. Tawaran Sumber

Seperti yang telah kita bincangkan sebelumnya, ejen menerbitkan maklumat sumber mereka kepada tuan. Pada gilirannya, master menawarkan sumber-sumber ini ke kerangka kerja yang berjalan di kluster. Proses ini dikenali sebagai tawaran sumber.

Tawaran sumber terdiri daripada dua bahagian - sumber dan atribut.

Sumber digunakan untuk menerbitkan maklumat perkakasan mesin ejen seperti memori, CPU, dan cakera.

Terdapat lima sumber yang telah ditentukan untuk setiap Ejen:

  • CPU
  • gpus
  • mem
  • cakera
  • pelabuhan

Nilai untuk sumber-sumber ini dapat ditentukan dalam salah satu daripada tiga jenis:

  • Skalar - Digunakan untuk mewakili maklumat berangka menggunakan nombor titik terapung untuk membolehkan nilai pecahan seperti memori 1.5G
  • Julat - Digunakan untuk mewakili julat nilai skalar - misalnya, julat port
  • Set - Digunakan untuk mewakili pelbagai nilai teks

Secara lalai, ejen Mesos cuba mengesan sumber ini dari mesin.

Namun, dalam beberapa keadaan, kita dapat mengkonfigurasi sumber tersuai pada ejen. Nilai-nilai untuk sumber-sumber khas seperti itu harus berada dalam salah satu jenis yang dibincangkan di atas.

Sebagai contoh, kami boleh memulakan ejen kami dengan sumber berikut:

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

Seperti yang dapat dilihat, kami telah mengkonfigurasi ejen dengan beberapa sumber yang telah ditentukan dan satu sumber tersuai bernama bug yang jenisnya ditetapkan .

Sebagai tambahan kepada sumber, ejen dapat menerbitkan atribut nilai kunci kepada tuan. Atribut ini bertindak sebagai metadata tambahan untuk ejen dan rangka kerja dalam menjadwalkan keputusan.

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

Dalam artikel ini, kami membincangkan perkongsian sumber antara aplikasi yang berjalan dalam kluster yang sama secara ringkas. Kami juga membincangkan bagaimana Apache Mesos membantu aplikasi mencapai penggunaan maksimum dengan pandangan abstrak sumber kluster seperti CPU dan memori.

Kemudian, kami membincangkan peruntukan sumber yang dinamik antara aplikasi berdasarkan pelbagai dasar dan peranan kewajaran. Mesos membolehkan aplikasi membuat keputusan penjadualan berdasarkan tawaran sumber dari ejen Mesos di kluster.

Akhirnya, kami melihat pelaksanaan kerangka Mesos di Jawa.

Seperti biasa, semua contoh boleh didapati di GitHub.