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/<role>/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.