You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2016/04/08 05:14:52 UTC

[3/3] mesos git commit: Added dominant share metrics to the DRF sorter.

Added dominant share metrics to the DRF sorter.

Review: https://reviews.apache.org/r/45534/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/69e2664c
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/69e2664c
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/69e2664c

Branch: refs/heads/master
Commit: 69e2664c6ef2e0eab85276d4a4eb8a0f8ade4ec3
Parents: b1e2ef0
Author: Benjamin Bannier <be...@mesosphere.io>
Authored: Thu Apr 7 18:02:53 2016 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Thu Apr 7 20:04:00 2016 -0700

----------------------------------------------------------------------
 docs/monitoring.md                          |  7 ++
 src/Makefile.am                             |  2 +
 src/master/allocator/mesos/hierarchical.hpp |  4 +-
 src/master/allocator/sorter/drf/metrics.cpp | 83 ++++++++++++++++++++
 src/master/allocator/sorter/drf/metrics.hpp | 62 +++++++++++++++
 src/master/allocator/sorter/drf/sorter.cpp  | 14 ++++
 src/master/allocator/sorter/drf/sorter.hpp  | 12 +++
 src/master/allocator/sorter/sorter.hpp      | 14 +++-
 src/tests/hierarchical_allocator_tests.cpp  | 97 ++++++++++++++++++++++++
 9 files changed, 293 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/69e2664c/docs/monitoring.md
----------------------------------------------------------------------
diff --git a/docs/monitoring.md b/docs/monitoring.md
index 76be328..38b4144 100644
--- a/docs/monitoring.md
+++ b/docs/monitoring.md
@@ -945,6 +945,13 @@ and resource allocations in the allocator.
 </tr>
 <tr>
   <td>
+  <code>allocator/mesos/roles/&lt;role&gt;/shares/dominant</code>
+  </td>
+  <td>Dominant resource share for the role, exposed as a percentage (0.0-1.0)</td>
+  <td>Gauge</td>
+</tr>
+<tr>
+  <td>
   <code>allocator/mesos/event_queue_dispatches</code>
   </td>
   <td>Number of dispatch events in the event queue</td>

http://git-wip-us.apache.org/repos/asf/mesos/blob/69e2664c/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 71c4308..b7f3f36 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -643,6 +643,7 @@ libmesos_no_3rdparty_la_SOURCES +=					\
   master/allocator/allocator.cpp					\
   master/allocator/mesos/hierarchical.cpp				\
   master/allocator/mesos/metrics.cpp					\
+  master/allocator/sorter/drf/metrics.cpp				\
   master/allocator/sorter/drf/sorter.cpp				\
   master/contender/contender.cpp					\
   master/contender/standalone.cpp					\
@@ -762,6 +763,7 @@ libmesos_no_3rdparty_la_SOURCES +=					\
   master/allocator/mesos/hierarchical.hpp				\
   master/allocator/mesos/metrics.hpp					\
   master/allocator/sorter/sorter.hpp					\
+  master/allocator/sorter/drf/metrics.hpp				\
   master/allocator/sorter/drf/sorter.hpp				\
   master/contender/standalone.hpp					\
   master/contender/zookeeper.hpp					\

http://git-wip-us.apache.org/repos/asf/mesos/blob/69e2664c/src/master/allocator/mesos/hierarchical.hpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/mesos/hierarchical.hpp b/src/master/allocator/mesos/hierarchical.hpp
index 29d0759..3f5dff7 100644
--- a/src/master/allocator/mesos/hierarchical.hpp
+++ b/src/master/allocator/mesos/hierarchical.hpp
@@ -475,7 +475,9 @@ class HierarchicalAllocatorProcess
 public:
   HierarchicalAllocatorProcess()
     : internal::HierarchicalAllocatorProcess(
-          []() -> Sorter* { return new RoleSorter(); },
+          [this]() -> Sorter* {
+            return new RoleSorter(this->self(), "allocator/mesos/roles/");
+          },
           []() -> Sorter* { return new FrameworkSorter(); },
           []() -> Sorter* { return new QuotaRoleSorter(); }) {}
 };

http://git-wip-us.apache.org/repos/asf/mesos/blob/69e2664c/src/master/allocator/sorter/drf/metrics.cpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/sorter/drf/metrics.cpp b/src/master/allocator/sorter/drf/metrics.cpp
new file mode 100644
index 0000000..c793f32
--- /dev/null
+++ b/src/master/allocator/sorter/drf/metrics.cpp
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "master/allocator/sorter/drf/metrics.hpp"
+
+#include <process/defer.hpp>
+
+#include <process/metrics/metrics.hpp>
+
+#include <stout/foreach.hpp>
+#include <stout/path.hpp>
+
+#include "master/allocator/sorter/drf/sorter.hpp"
+
+using std::string;
+
+using process::UPID;
+using process::defer;
+
+using process::metrics::Gauge;
+
+namespace mesos {
+namespace internal {
+namespace master {
+namespace allocator {
+
+Metrics::Metrics(
+    const UPID& _context,
+    DRFSorter& _sorter,
+    const std::string& _prefix)
+  : context(_context),
+    sorter(&_sorter),
+    prefix(_prefix) {}
+
+
+Metrics::~Metrics()
+{
+  foreachvalue (const Gauge& gauge, dominantShares) {
+    process::metrics::remove(gauge);
+  }
+}
+
+
+void Metrics::add(const string& client)
+{
+  CHECK(!dominantShares.contains(client));
+
+  Gauge gauge(
+      path::join(prefix, client, "/shares/", "/dominant"),
+      defer(context, [this, client]() {
+        return sorter->calculateShare(client);
+      }));
+
+  dominantShares.put(client, gauge);
+  process::metrics::add(gauge);
+}
+
+
+void Metrics::remove(const string& client)
+{
+  CHECK(dominantShares.contains(client));
+
+  process::metrics::remove(dominantShares.at(client));
+  dominantShares.erase(client);
+}
+
+} // namespace allocator {
+} // namespace master {
+} // namespace internal {
+} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/69e2664c/src/master/allocator/sorter/drf/metrics.hpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/sorter/drf/metrics.hpp b/src/master/allocator/sorter/drf/metrics.hpp
new file mode 100644
index 0000000..61568cb
--- /dev/null
+++ b/src/master/allocator/sorter/drf/metrics.hpp
@@ -0,0 +1,62 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __MASTER_ALLOCATOR_SORTER_DRF_SORTER_METRICS_HPP__
+#define __MASTER_ALLOCATOR_SORTER_DRF_SORTER_METRICS_HPP__
+
+#include <string>
+
+#include <process/pid.hpp>
+
+#include <process/metrics/gauge.hpp>
+
+#include <stout/hashmap.hpp>
+
+namespace mesos {
+namespace internal {
+namespace master {
+namespace allocator {
+
+class DRFSorter;
+
+struct Metrics
+{
+  explicit Metrics(
+      const process::UPID& context,
+      DRFSorter& sorter,
+      const std::string& prefix);
+
+  ~Metrics();
+
+  void add(const std::string& client);
+  void remove(const std::string& client);
+
+  const process::UPID context;
+
+  DRFSorter* sorter;
+
+  const std::string prefix;
+
+  // Dominant share of each client.
+  hashmap<std::string, process::metrics::Gauge> dominantShares;
+};
+
+} // namespace allocator {
+} // namespace master {
+} // namespace internal {
+} // namespace mesos {
+
+#endif  // __MASTER_ALLOCATOR_SORTER_DRF_SORTER_METRICS_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/69e2664c/src/master/allocator/sorter/drf/sorter.cpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/sorter/drf/sorter.cpp b/src/master/allocator/sorter/drf/sorter.cpp
index c14f9a4..d0efa4d 100644
--- a/src/master/allocator/sorter/drf/sorter.cpp
+++ b/src/master/allocator/sorter/drf/sorter.cpp
@@ -39,6 +39,12 @@ bool DRFComparator::operator()(const Client& client1, const Client& client2)
 }
 
 
+DRFSorter::DRFSorter(
+    const process::UPID& allocator,
+    const std::string& metricsPrefix)
+  : metrics(Metrics(allocator, *this, metricsPrefix)) {}
+
+
 void DRFSorter::add(const string& name, double weight)
 {
   Client client(name, 0, 0);
@@ -46,6 +52,10 @@ void DRFSorter::add(const string& name, double weight)
 
   allocations[name] = Allocation();
   weights[name] = weight;
+
+  if (metrics.isSome()) {
+    metrics->add(name);
+  }
 }
 
 
@@ -66,6 +76,10 @@ void DRFSorter::remove(const string& name)
 
   allocations.erase(name);
   weights.erase(name);
+
+  if (metrics.isSome()) {
+    metrics->remove(name);
+  }
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/69e2664c/src/master/allocator/sorter/drf/sorter.hpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/sorter/drf/sorter.hpp b/src/master/allocator/sorter/drf/sorter.hpp
index f316bb5..05d5205 100644
--- a/src/master/allocator/sorter/drf/sorter.hpp
+++ b/src/master/allocator/sorter/drf/sorter.hpp
@@ -24,6 +24,8 @@
 
 #include <stout/hashmap.hpp>
 
+#include "master/allocator/sorter/drf/metrics.hpp"
+
 #include "master/allocator/sorter/sorter.hpp"
 
 
@@ -61,6 +63,12 @@ struct DRFComparator
 class DRFSorter : public Sorter
 {
 public:
+  DRFSorter() = default;
+
+  explicit DRFSorter(
+      const process::UPID& allocator,
+      const std::string& metricsPrefix);
+
   virtual ~DRFSorter() {}
 
   virtual void add(const std::string& name, double weight = 1);
@@ -160,6 +168,10 @@ private:
 
   // Maps client names to the resources they have been allocated.
   hashmap<std::string, Allocation> allocations;
+
+  // Metrics are optionally exposed by the sorter.
+  friend Metrics;
+  Option<Metrics> metrics;
 };
 
 } // namespace allocator {

http://git-wip-us.apache.org/repos/asf/mesos/blob/69e2664c/src/master/allocator/sorter/sorter.hpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/sorter/sorter.hpp b/src/master/allocator/sorter/sorter.hpp
index e2338d5..9e04adf 100644
--- a/src/master/allocator/sorter/sorter.hpp
+++ b/src/master/allocator/sorter/sorter.hpp
@@ -17,12 +17,15 @@
 #ifndef __MASTER_ALLOCATOR_SORTER_SORTER_HPP__
 #define __MASTER_ALLOCATOR_SORTER_SORTER_HPP__
 
+#include <functional>
 #include <list>
 #include <string>
 
 #include <mesos/resources.hpp>
 #include <mesos/type_utils.hpp>
 
+#include <process/pid.hpp>
+
 namespace mesos {
 namespace internal {
 namespace master {
@@ -38,7 +41,16 @@ namespace allocator {
 class Sorter
 {
 public:
-  virtual ~Sorter() {}
+  Sorter() = default;
+
+  // Provides the allocator's execution context (via a UPID)
+  // and a name prefix in order to support metrics within the
+  // sorter implementation.
+  explicit Sorter(
+      const process::UPID& allocator,
+      const std::string& metricsPrefix) {}
+
+  virtual ~Sorter() = default;
 
   // Adds a client to allocate resources to. A client
   // may be a user or a framework.

http://git-wip-us.apache.org/repos/asf/mesos/blob/69e2664c/src/tests/hierarchical_allocator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/hierarchical_allocator_tests.cpp b/src/tests/hierarchical_allocator_tests.cpp
index 964570c..a5dd57a 100644
--- a/src/tests/hierarchical_allocator_tests.cpp
+++ b/src/tests/hierarchical_allocator_tests.cpp
@@ -2745,6 +2745,103 @@ TEST_F(HierarchicalAllocatorTest, ActiveOfferFiltersMetrics)
 }
 
 
+// Verifies that per-role dominant share metrics are correctly reported.
+TEST_F(HierarchicalAllocatorTest, DominantShareMetrics)
+{
+  // Pausing the clock is not necessary, but ensures that the test
+  // doesn't rely on the batch allocation in the allocator, which
+  // would slow down the test.
+  Clock::pause();
+
+  initialize();
+
+  // Register one agent and one framework. The framework will
+  // immediately receive receive an offer and make it have the
+  // maximum possible dominant share.
+  SlaveInfo agent1 = createSlaveInfo("cpus:1;mem:1024");
+  allocator->addSlave(agent1.id(), agent1, None(), agent1.resources(), {});
+
+  FrameworkInfo framework1 = createFrameworkInfo("roleA");
+  allocator->addFramework(framework1.id(), framework1, {});
+  Clock::settle();
+
+  JSON::Object expected;
+
+  expected.values = {
+      {"allocator/mesos/roles/roleA/shares/dominant", 1},
+  };
+
+  JSON::Value metrics = Metrics();
+  EXPECT_TRUE(metrics.contains(expected));
+
+  // Decline the offered resources and expect a zero share.
+  Future<Allocation> allocation = allocations.get();
+  AWAIT_READY(allocation);
+  allocator->recoverResources(
+      allocation->frameworkId,
+      agent1.id(),
+      allocation->resources.get(agent1.id()).get(),
+      None());
+  Clock::settle();
+
+  expected.values = {
+      {"allocator/mesos/roles/roleA/shares/dominant", 0},
+  };
+
+  metrics = Metrics();
+  EXPECT_TRUE(metrics.contains(expected));
+
+  // Register a second framework. This framework will receive
+  // offers as `framework1` has just declined an offer and the
+  // implicit filter has not yet timed out. The new framework
+  // will have the full share.
+  FrameworkInfo framework2 = createFrameworkInfo("roleB");
+  allocator->addFramework(framework2.id(), framework2, {});
+  Clock::settle();
+
+  expected.values = {
+      {"allocator/mesos/roles/roleA/shares/dominant", 0},
+      {"allocator/mesos/roles/roleB/shares/dominant", 1},
+  };
+
+  metrics = Metrics();
+  EXPECT_TRUE(metrics.contains(expected));
+
+  // Add a second, identical agent. Now `framework1` will
+  // receive an offer since it has the lowest dominant
+  // share. After the offer the dominant shares of
+  // `framework1` and `framework2` are equal.
+  SlaveInfo agent2 = createSlaveInfo("cpus:1;mem:1024");
+  allocator->addSlave(agent2.id(), agent2, None(), agent2.resources(), {});
+  Clock::settle();
+
+  expected.values = {
+      {"allocator/mesos/roles/roleA/shares/dominant", 0.5},
+      {"allocator/mesos/roles/roleB/shares/dominant", 0.5},
+  };
+
+  metrics = Metrics();
+  EXPECT_TRUE(metrics.contains(expected));
+
+  // Removing `framework2` frees up its allocated resources. The
+  // corresponding metric is removed when the last framework in
+  // the role is removed.
+  allocator->removeFramework(framework2.id());
+  Clock::settle();
+
+  expected.values = {
+      {"allocator/mesos/roles/roleA/shares/dominant", 0.5},
+  };
+
+  metrics = Metrics();
+  EXPECT_TRUE(metrics.contains(expected));
+
+  ASSERT_TRUE(metrics.is<JSON::Object>());
+  map<string, JSON::Value> values = metrics.as<JSON::Object>().values;
+  EXPECT_EQ(0u, values.count("allocator/mesos/roles/roleB/shares/dominant"));
+}
+
+
 // This test ensures that resource allocation is done according to each role's
 // weight. This is done by having six agents and three frameworks and making
 // sure each framework gets the appropriate number of resources.