Panduan untuk Apache Mesos

1. Ikhtisar

Kami biasanya menerapkan berbagai aplikasi pada kluster mesin yang sama. Misalnya, saat ini umum untuk memiliki mesin pemroses terdistribusi seperti Apache Spark atau Apache Flink dengan database terdistribusi seperti Apache Cassandra dalam kluster yang sama.

Apache Mesos adalah platform yang memungkinkan berbagi sumber daya yang efektif antara aplikasi semacam itu.

Pada artikel ini, pertama-tama kita akan membahas beberapa masalah alokasi sumber daya dalam aplikasi yang digunakan di cluster yang sama. Nanti, kita akan melihat bagaimana Apache Mesos menyediakan pemanfaatan sumber daya yang lebih baik antar aplikasi.

2. Berbagi Cluster

Banyak aplikasi perlu berbagi cluster. Secara umum, ada dua pendekatan umum:

  • Partisi cluster secara statis dan jalankan aplikasi di setiap partisi
  • Alokasikan satu set mesin ke aplikasi

Meskipun pendekatan ini memungkinkan aplikasi untuk berjalan secara independen satu sama lain, itu tidak mencapai pemanfaatan sumber daya yang tinggi.

Misalnya, pertimbangkan aplikasi yang berjalan hanya untuk waktu yang singkat diikuti dengan periode tidak aktif. Sekarang, karena kami telah mengalokasikan mesin atau partisi statis ke aplikasi ini, kami memiliki sumber daya yang tidak digunakan selama periode tidak aktif.

Kami dapat mengoptimalkan pemanfaatan sumber daya dengan mengalokasikan kembali sumber daya gratis selama periode tidak aktif ke aplikasi lain.

Apache Mesos membantu alokasi sumber daya dinamis antar aplikasi.

3. Apache Mesos

Dengan kedua pendekatan berbagi klaster yang kita diskusikan di atas, aplikasi hanya mengetahui sumber daya dari partisi atau mesin tertentu yang mereka jalankan. Namun, Apache Mesos menyediakan tampilan abstrak dari semua sumber daya di cluster ke aplikasi.

Seperti yang akan kita lihat sebentar lagi, Mesos bertindak sebagai antarmuka antara mesin dan aplikasi. Ini menyediakan aplikasi dengan sumber daya yang tersedia di semua mesin di cluster. Ini sering memperbarui informasi ini untuk menyertakan sumber daya yang dibebaskan oleh aplikasi yang telah mencapai status penyelesaian. Hal ini memungkinkan aplikasi membuat keputusan terbaik tentang tugas mana yang akan dijalankan pada mesin mana.

Untuk memahami cara kerja Mesos, mari kita lihat arsitekturnya:

Gambar ini adalah bagian dari dokumentasi resmi untuk Mesos (sumber). Di sini, Hadoop dan MPI adalah dua aplikasi yang berbagi cluster.

Kami akan membicarakan setiap komponen yang ditampilkan di sini di beberapa bagian berikutnya.

3.1. Mesos Master

Master adalah komponen inti dalam penyiapan ini dan menyimpan status sumber daya saat ini di cluster. Selain itu, ia bertindak sebagai orkestrator antara agen dan aplikasi dengan meneruskan informasi tentang hal-hal seperti sumber daya dan tugas.

Karena kegagalan dalam master mengakibatkan hilangnya status tentang sumber daya dan tugas, kami menerapkannya dalam konfigurasi ketersediaan tinggi. Seperti yang dapat dilihat pada diagram di atas, Mesos menyebarkan daemon master standby bersama dengan satu leader. Daemon ini mengandalkan Zookeeper untuk memulihkan status jika terjadi kegagalan.

3.2. Agen Mesos

Cluster Mesos harus menjalankan agen di setiap mesin. Agen ini melaporkan sumber daya mereka ke master secara berkala dan pada gilirannya, menerima tugas yang telah dijadwalkan untuk dijalankan oleh aplikasi . Siklus ini berulang setelah tugas yang dijadwalkan selesai atau hilang.

Kita akan melihat bagaimana aplikasi menjadwalkan dan menjalankan tugas pada agen ini di bagian berikut.

3.3. Kerangka Mesos

Mesos memungkinkan aplikasi untuk mengimplementasikan komponen abstrak yang berinteraksi dengan Master untuk menerima sumber daya yang tersedia di cluster dan terlebih lagi membuat keputusan penjadwalan berdasarkan mereka. Komponen ini dikenal sebagai kerangka kerja.

Kerangka Mesos terdiri dari dua sub-komponen:

  • Scheduler - Memungkinkan aplikasi untuk menjadwalkan tugas berdasarkan sumber daya yang tersedia di semua agen
  • Pelaksana - Berjalan di semua agen dan berisi semua informasi yang diperlukan untuk menjalankan tugas terjadwal pada agen itu

Keseluruhan proses ini digambarkan dengan aliran ini:

Pertama, agen melaporkan sumber dayanya kepada master. Saat ini, master menawarkan sumber daya ini ke semua penjadwal terdaftar. Proses ini dikenal sebagai penawaran sumber daya, dan kita akan membahasnya secara mendetail di bagian selanjutnya.

Penjadwal kemudian memilih agen terbaik dan menjalankan berbagai tugas di dalamnya melalui Master. Segera setelah pelaksana menyelesaikan tugas yang diberikan, agen menerbitkan kembali sumber daya mereka ke master. Master mengulangi proses berbagi sumber daya ini untuk semua kerangka kerja di kluster.

Mesos memungkinkan aplikasi untuk mengimplementasikan penjadwal dan pelaksana kustom mereka dalam berbagai bahasa pemrograman. Pelaksanaan Sebuah Java dari scheduler harus menerapkan yang Scheduler antarmuka :

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, sebagian besar terdiri dari berbagai metode panggilan balik untuk komunikasi dengan master pada khususnya.

Demikian pula, implementasi pelaksana harus mengimplementasikan antarmuka 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) { } }

Kita akan melihat versi operasional dari penjadwal dan pelaksana di bagian selanjutnya.

4. Manajemen Sumber Daya

4.1. Penawaran Sumber Daya

Seperti yang telah kita diskusikan sebelumnya, agen mempublikasikan informasi sumber daya mereka ke master. Pada gilirannya, master menawarkan sumber daya ini ke kerangka kerja yang berjalan di cluster. Proses ini dikenal sebagai penawaran sumber daya.

Tawaran sumber daya terdiri dari dua bagian - sumber daya dan atribut.

Sumber daya digunakan untuk mempublikasikan informasi perangkat keras mesin agen seperti memori, CPU, dan disk.

Ada lima sumber daya yang telah ditentukan untuk setiap Agen:

  • cpu
  • gpus
  • mem
  • disk
  • pelabuhan

Nilai untuk sumber daya ini dapat ditentukan dalam salah satu dari tiga jenis:

  • Skalar - Digunakan untuk merepresentasikan informasi numerik menggunakan angka floating point untuk memungkinkan nilai pecahan seperti memori 1,5G
  • Range - Digunakan untuk mewakili kisaran nilai skalar - misalnya, kisaran port
  • Set - Digunakan untuk mewakili beberapa nilai teks

Secara default, agen Mesos mencoba mendeteksi sumber daya ini dari mesin.

Namun, dalam beberapa situasi, kami dapat mengonfigurasi sumber daya kustom di agen. Nilai untuk sumber daya ubahsuaian seperti itu lagi-lagi harus dalam salah satu jenis yang dibahas di atas.

Misalnya, kami dapat memulai agen kami dengan sumber daya ini:

--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 mengonfigurasi agen dengan beberapa sumber daya yang telah ditentukan sebelumnya dan satu sumber daya khusus bernama bug yang merupakan tipe set .

Selain resource, agen dapat memublikasikan atribut nilai kunci ke master. Atribut ini bertindak sebagai metadata tambahan untuk agen dan kerangka bantuan dalam keputusan penjadwalan.

Contoh yang berguna adalah menambahkan agen ke dalam rak atau zona yang berbeda dan kemudian menjadwalkan berbagai tugas di rak atau zona yang sama untuk mencapai lokalitas data:

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

Mirip dengan sumber daya, nilai untuk atribut bisa berupa skalar, rentang, atau jenis teks.

4.2. Peran Sumber Daya

Banyak sistem operasi modern mendukung banyak pengguna. Demikian pula, Mesos juga mendukung banyak pengguna di cluster yang sama. Pengguna ini dikenal sebagai peran . Kami dapat mempertimbangkan setiap peran sebagai konsumen sumber daya dalam sebuah cluster.

Karenanya, agen Mesos dapat mempartisi sumber daya di bawah peran yang berbeda berdasarkan strategi alokasi yang berbeda. Selain itu, framework dapat menggunakan peran ini dalam cluster dan memiliki kontrol yang sangat baik atas resource di bawah peran yang berbeda.

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

Pada artikel ini, kami membahas berbagi sumber daya antara aplikasi yang berjalan di cluster yang sama secara singkat. Kami juga membahas bagaimana Apache Mesos membantu aplikasi mencapai pemanfaatan maksimum dengan tampilan abstrak sumber daya cluster seperti CPU dan memori.

Kemudian, kami membahas alokasi dinamis sumber daya antara aplikasi berdasarkan berbagai kebijakan dan peran keadilan. Mesos memungkinkan aplikasi untuk membuat keputusan penjadwalan berdasarkan penawaran sumber daya dari agen Mesos di cluster.

Akhirnya, kami melihat implementasi kerangka Mesos di Jawa.

Seperti biasa, semua contoh tersedia di GitHub.