You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by jo...@apache.org on 2015/11/16 17:18:17 UTC

[4/5] mesos git commit: Quota: Introduced capacity heuristic for quota set requests.

Quota: Introduced capacity heuristic for quota set requests.

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


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

Branch: refs/heads/master
Commit: 8057cdcda27a6749020302f8dc56c4c8a3921922
Parents: 20bfb61
Author: Alexander Rukletsov <ru...@gmail.com>
Authored: Mon Nov 16 11:40:21 2015 +0100
Committer: Joris Van Remoortere <jo...@gmail.com>
Committed: Mon Nov 16 17:05:17 2015 +0100

----------------------------------------------------------------------
 src/master/master.hpp        | 24 ++++++++++++--
 src/master/quota_handler.cpp | 67 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 88 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/8057cdcd/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 64edf14..dc5790a 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -847,8 +847,6 @@ private:
   class QuotaHandler
   {
   public:
-    // TODO(joerg84): For now this is just a stub. It will be filled as
-    // part of MESOS-1791.
     explicit QuotaHandler(Master* _master) : master(_master)
     {
       CHECK_NOTNULL(master);
@@ -874,6 +872,28 @@ private:
     }
 
   private:
+    // Heuristically tries to determine whether a quota request could
+    // reasonably be satisfied given the current cluster capacity. The
+    // goal is to determine whether a user may accidentally request an
+    // amount of resources that would prevent frameworks without quota
+    // from getting any offers. A force flag will allow users to bypass
+    // this check.
+    //
+    // The heuristic tests whether the total quota, including the new
+    // request, does not exceed the sum of non-static cluster resources,
+    // i.e. the following inequality holds:
+    //   total - statically reserved >= total quota + quota request
+    //
+    // Please be advised that:
+    //   * It is up to an allocator how to satisfy quota (for example,
+    //     what resources to account towards quota, as well as which
+    //     resources to consider allocatable for quota).
+    //   * Even if there are enough resources at the moment of this check,
+    //     agents may terminate at any time, rendering the cluster under
+    //     quota.
+    Option<Error> capacityHeuristic(
+        const mesos::quota::QuotaInfo& request) const;
+
     // To perform actions related to quota management, we require access to the
     // master data structures. No synchronization primitives are needed here
     // since `QuotaHandler`'s functions are invoked in the Master's actor.

http://git-wip-us.apache.org/repos/asf/mesos/blob/8057cdcd/src/master/quota_handler.cpp
----------------------------------------------------------------------
diff --git a/src/master/quota_handler.cpp b/src/master/quota_handler.cpp
index da8c0ff..3db3c55 100644
--- a/src/master/quota_handler.cpp
+++ b/src/master/quota_handler.cpp
@@ -88,6 +88,67 @@ static Try<QuotaInfo> createQuotaInfo(
 }
 
 
+Option<Error> Master::QuotaHandler::capacityHeuristic(
+    const QuotaInfo& request) const
+{
+  VLOG(1) << "Performing capacity heuristic check for a set quota request";
+
+  // This should have been validated earlier.
+  CHECK(master->roles.contains(request.role()));
+  CHECK(!master->quotas.contains(request.role()));
+
+  // Calculate the total amount of resources requested by all quotas
+  // (including the request) in the cluster.
+  // NOTE: We have validated earlier that the quota for the role in the
+  // request does not exist, hence `master->quotas` is guaranteed not to
+  // contain the request role's quota yet.
+  // TODO(alexr): Relax this constraint once we allow updating quotas.
+  Resources totalQuota = request.guarantee();
+  foreachvalue (const Quota& quota, master->quotas) {
+    totalQuota += quota.info.guarantee();
+  }
+
+  // Remove roles via `flatten()` to facilitate resource math.
+  totalQuota = totalQuota.flatten();
+
+  // Determine whether the total quota, including the new request, does
+  // not exceed the sum of non-static cluster resources.
+  // NOTE: We do not necessarily calculate the full sum of non-static
+  // cluster resources. We apply the early termination logic as it can
+  // reduce the cost of the function significantly. This early exit does
+  // not influence the declared inequality check.
+  Resources nonStaticClusterResources;
+  foreachvalue (Slave* slave, master->slaves.registered) {
+    // We do not consider disconnected or inactive agents, because they
+    // do not participate in resource allocation.
+    if (!slave->connected || !slave->active) {
+      continue;
+    }
+
+    // NOTE: Dynamic reservations are not excluded here because they do
+    // not show up in `SlaveInfo` resources. In contrast to static
+    // reservations, dynamic reservations may be unreserved at any time,
+    // hence making resources available for quota'ed frameworks.
+    Resources nonStaticAgentResources =
+      Resources(slave->info.resources()).unreserved();
+
+    nonStaticClusterResources += nonStaticAgentResources;
+
+    // If we have found enough resources to satisfy the inequality, then
+    // we can return early.
+    if (nonStaticClusterResources.contains(totalQuota)) {
+      return None();
+    }
+  }
+
+  // If we reached this point, there are not enough available resources
+  // in the cluster, hence the request does not pass the heuristic.
+  return Error(
+      "Not enough available cluster capacity to reasonably satisfy quota "
+      "request; the force flag can be used to override this check");
+}
+
+
 Future<http::Response> Master::QuotaHandler::set(
     const http::Request& request) const
 {
@@ -159,7 +220,11 @@ Future<http::Response> Master::QuotaHandler::set(
   const QuotaInfo& quotaInfo = create.get();
 
   // Validate whether a quota request can be satisfied.
-  // TODO(alexr): Implement as per MESOS-3073.
+  Option<Error> error = capacityHeuristic(quotaInfo);
+  if (error.isSome()) {
+    return Conflict("Heuristic capacity check for set quota request failed: " +
+                    error.get().message);
+  }
 
   // Populate master's quota-related local state. We do this before updating
   // the registry in order to make sure that we are not already trying to