aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2020-11-27 11:46:17 +0100
committerMartin Polden <mpolden@mpolden.no>2020-12-01 10:50:16 +0100
commitfa2196703ab3587fcda0735aeb4f9c2aefe55156 (patch)
tree89c96381c7afe1f7d45c8178f6eb60785d59808d
parent1deec4e9bf50ff882e39079ae61114bbefaa4b6f (diff)
Use stateful property
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java33
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java18
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java5
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java3
6 files changed, 32 insertions, 35 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java
index b1213b2da41..9eb4b796970 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java
@@ -26,20 +26,19 @@ public class AllocatableClusterResources {
private final NodeResources realResources;
private final NodeResources advertisedResources;
- private final ClusterSpec.Type clusterType;
+ private final ClusterSpec clusterSpec;
private final double fulfilment;
/** Fake allocatable resources from requested capacity */
public AllocatableClusterResources(ClusterResources requested,
- ClusterSpec.Type clusterType,
- boolean exclusive,
+ ClusterSpec clusterSpec,
NodeRepository nodeRepository) {
this.nodes = requested.nodes();
this.groups = requested.groups();
- this.realResources = nodeRepository.resourcesCalculator().requestToReal(requested.nodeResources(), exclusive);
+ this.realResources = nodeRepository.resourcesCalculator().requestToReal(requested.nodeResources(), clusterSpec.isExclusive());
this.advertisedResources = requested.nodeResources();
- this.clusterType = clusterType;
+ this.clusterSpec = clusterSpec;
this.fulfilment = 1;
}
@@ -48,19 +47,19 @@ public class AllocatableClusterResources {
this.groups = (int)nodes.stream().map(node -> node.allocation().get().membership().cluster().group()).distinct().count();
this.realResources = averageRealResourcesOf(nodes, nodeRepository, exclusive); // Average since we average metrics over nodes
this.advertisedResources = nodes.get(0).resources();
- this.clusterType = nodes.get(0).allocation().get().membership().cluster().type();
+ this.clusterSpec = nodes.get(0).allocation().get().membership().cluster();
this.fulfilment = 1;
}
public AllocatableClusterResources(ClusterResources realResources,
NodeResources advertisedResources,
NodeResources idealResources,
- ClusterSpec.Type clusterType) {
+ ClusterSpec clusterSpec) {
this.nodes = realResources.nodes();
this.groups = realResources.groups();
this.realResources = realResources.nodeResources();
this.advertisedResources = advertisedResources;
- this.clusterType = clusterType;
+ this.clusterSpec = clusterSpec;
this.fulfilment = fulfilment(realResources.nodeResources(), idealResources);
}
@@ -88,7 +87,7 @@ public class AllocatableClusterResources {
return (int)Math.ceil((double)nodes / groups);
}
- public ClusterSpec.Type clusterType() { return clusterType; }
+ public ClusterSpec clusterSpec() { return clusterSpec; }
public double cost() { return nodes * advertisedResources.cost(); }
@@ -133,23 +132,23 @@ public class AllocatableClusterResources {
}
public static Optional<AllocatableClusterResources> from(ClusterResources wantedResources,
- boolean exclusive,
- ClusterSpec.Type clusterType,
+ ClusterSpec clusterSpec,
Limits applicationLimits,
NodeRepository nodeRepository) {
var systemLimits = new NodeResourceLimits(nodeRepository);
- if ( !exclusive && !nodeRepository.zone().getCloud().dynamicProvisioning()) {
+ boolean exclusive = clusterSpec.isExclusive();
+ if ( !clusterSpec.isExclusive() && !nodeRepository.zone().getCloud().dynamicProvisioning()) {
// We decide resources: Add overhead to what we'll request (advertised) to make sure real becomes (at least) cappedNodeResources
NodeResources advertisedResources = nodeRepository.resourcesCalculator().realToRequest(wantedResources.nodeResources(), exclusive);
- advertisedResources = systemLimits.enlargeToLegal(advertisedResources, clusterType, exclusive); // Attempt to ask for something legal
+ advertisedResources = systemLimits.enlargeToLegal(advertisedResources, clusterSpec.type(), exclusive); // Attempt to ask for something legal
advertisedResources = applicationLimits.cap(advertisedResources); // Overrides other conditions, even if it will then fail
NodeResources realResources = nodeRepository.resourcesCalculator().requestToReal(advertisedResources, exclusive); // ... thus, what we really get may change
- if ( ! systemLimits.isWithinRealLimits(realResources, clusterType)) return Optional.empty();
+ if ( ! systemLimits.isWithinRealLimits(realResources, clusterSpec.type())) return Optional.empty();
if (matchesAny(nodeRepository.flavors().getFlavors(), advertisedResources))
return Optional.of(new AllocatableClusterResources(wantedResources.with(realResources),
advertisedResources,
wantedResources.nodeResources(),
- clusterType));
+ clusterSpec));
else
return Optional.empty();
}
@@ -172,11 +171,11 @@ public class AllocatableClusterResources {
}
if ( ! between(applicationLimits.min().nodeResources(), applicationLimits.max().nodeResources(), advertisedResources)) continue;
- if ( ! systemLimits.isWithinRealLimits(realResources, clusterType)) continue;
+ if ( ! systemLimits.isWithinRealLimits(realResources, clusterSpec.type())) continue;
var candidate = new AllocatableClusterResources(wantedResources.with(realResources),
advertisedResources,
wantedResources.nodeResources(),
- clusterType);
+ clusterSpec);
if (best.isEmpty() || candidate.preferableTo(best.get()))
best = Optional.of(candidate);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java
index e57011b0e4a..fb97e803a35 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java
@@ -58,7 +58,7 @@ public class AllocationOptimizer {
groups,
nodeResourcesWith(nodesAdjustedForRedundancy, groupsAdjustedForRedundancy, limits, current, target));
- var allocatableResources = AllocatableClusterResources.from(next, exclusive, current.clusterType(), limits, nodeRepository);
+ var allocatableResources = AllocatableClusterResources.from(next, current.clusterSpec(), limits, nodeRepository);
if (allocatableResources.isEmpty()) continue;
if (bestAllocation.isEmpty() || allocatableResources.get().preferableTo(bestAllocation.get()))
bestAllocation = allocatableResources;
@@ -79,7 +79,7 @@ public class AllocationOptimizer {
int groupSize = nodes / groups;
- if (current.clusterType().isContent()) { // load scales with node share of content
+ if (current.clusterSpec().isStateful()) { // load scales with node share of content
// The fixed cost portion of cpu does not scale with changes to the node count
// TODO: Only for the portion of cpu consumed by queries
double cpuPerGroup = fixedCpuCostFraction * target.nodeCpu() +
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
index 023eb5860ee..8fcba452d26 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
@@ -59,7 +59,7 @@ public class Autoscaler {
}
private Advice autoscale(Cluster cluster, List<Node> clusterNodes, Limits limits, boolean exclusive) {
- ClusterSpec.Type clusterType = clusterNodes.get(0).allocation().get().membership().cluster().type();
+ ClusterSpec clusterSpec = clusterNodes.get(0).allocation().get().membership().cluster();
if ( ! stable(clusterNodes, nodeRepository))
return Advice.none("Cluster change in progress");
@@ -69,7 +69,7 @@ public class Autoscaler {
ClusterTimeseries clusterTimeseries = new ClusterTimeseries(cluster, clusterNodes, metricsDb, nodeRepository);
int measurementsPerNode = clusterTimeseries.measurementsPerNode();
- if (measurementsPerNode < minimumMeasurementsPerNode(clusterType))
+ if (measurementsPerNode < minimumMeasurementsPerNode(clusterSpec))
return Advice.none("Collecting more data before making new scaling decisions" +
": Has " + measurementsPerNode + " data points per node" +
"(all: " + clusterTimeseries.measurementCount +
@@ -124,14 +124,14 @@ public class Autoscaler {
}
private boolean recentlyScaled(Cluster cluster, List<Node> clusterNodes) {
- Duration downscalingDelay = downscalingDelay(clusterNodes.get(0).allocation().get().membership().cluster().type());
+ Duration downscalingDelay = downscalingDelay(clusterNodes.get(0).allocation().get().membership().cluster());
return cluster.lastScalingEvent().map(event -> event.at()).orElse(Instant.MIN)
.isAfter(nodeRepository.clock().instant().minus(downscalingDelay));
}
/** The duration of the window we need to consider to make a scaling decision. See also minimumMeasurementsPerNode */
- static Duration scalingWindow(ClusterSpec.Type clusterType) {
- if (clusterType.isContent()) return Duration.ofHours(12);
+ static Duration scalingWindow(ClusterSpec cluster) {
+ if (cluster.isStateful()) return Duration.ofHours(12);
return Duration.ofMinutes(30);
}
@@ -140,8 +140,8 @@ public class Autoscaler {
}
/** Measurements are currently taken once a minute. See also scalingWindow */
- static int minimumMeasurementsPerNode(ClusterSpec.Type clusterType) {
- if (clusterType.isContent()) return 60;
+ static int minimumMeasurementsPerNode(ClusterSpec cluster) {
+ if (cluster.isStateful()) return 60;
return 7;
}
@@ -149,8 +149,8 @@ public class Autoscaler {
* We should wait a while before scaling down after a scaling event as a peak in usage
* indicates more peaks may arrive in the near future.
*/
- static Duration downscalingDelay(ClusterSpec.Type clusterType) {
- if (clusterType.isContent()) return Duration.ofHours(12);
+ static Duration downscalingDelay(ClusterSpec cluster) {
+ if (cluster.isStateful()) return Duration.ofHours(12);
return Duration.ofHours(1);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java
index 1983162f121..2b4ba3fbbcb 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java
@@ -7,7 +7,6 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.applications.Cluster;
import java.time.Instant;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -33,8 +32,8 @@ public class ClusterTimeseries {
public ClusterTimeseries(Cluster cluster, List<Node> clusterNodes, MetricsDb db, NodeRepository nodeRepository) {
this.clusterNodes = clusterNodes;
- ClusterSpec.Type clusterType = clusterNodes.get(0).allocation().get().membership().cluster().type();
- var timeseries = db.getNodeTimeseries(nodeRepository.clock().instant().minus(Autoscaler.scalingWindow(clusterType)),
+ ClusterSpec clusterSpec = clusterNodes.get(0).allocation().get().membership().cluster();
+ var timeseries = db.getNodeTimeseries(nodeRepository.clock().instant().minus(Autoscaler.scalingWindow(clusterSpec)),
clusterNodes.stream().map(Node::hostname).collect(Collectors.toSet()));
Map<String, Instant> startTimePerNode = metricStartTimes(cluster, clusterNodes, timeseries, nodeRepository);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
index 68e11c4c995..bc164dc37e0 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
@@ -203,7 +203,7 @@ class NodeAllocation {
* Such nodes will be marked retired during finalization of the list of accepted nodes.
* The conditions for this are:
*
- * This is a content or combined node. These must always be retired before being removed to allow the cluster to
+ * This is a stateful node. These must always be retired before being removed to allow the cluster to
* migrate away data.
*
* This is a container node and it is not desired due to having the wrong flavor. In this case this
@@ -218,7 +218,7 @@ class NodeAllocation {
if (candidate.allocation().get().membership().retired()) return true; // don't second-guess if already retired
if (! requestedNodes.considerRetiring()) return false;
- return cluster.type().isContent() ||
+ return cluster.isStateful() ||
(cluster.type() == ClusterSpec.Type.container && !hasCompatibleFlavor(candidate));
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
index ede6f4ef250..a6d68243160 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
@@ -29,7 +29,6 @@ import com.yahoo.vespa.hosted.provision.autoscale.AllocatableClusterResources;
import com.yahoo.vespa.hosted.provision.autoscale.AllocationOptimizer;
import com.yahoo.vespa.hosted.provision.autoscale.Limits;
import com.yahoo.vespa.hosted.provision.autoscale.ResourceTarget;
-import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.filter.ApplicationFilter;
import com.yahoo.vespa.hosted.provision.node.filter.NodeHostFilter;
@@ -168,7 +167,7 @@ public class NodeRepositoryProvisioner implements Provisioner {
boolean firstDeployment = nodes.isEmpty();
AllocatableClusterResources currentResources =
firstDeployment // start at min, preserve current resources otherwise
- ? new AllocatableClusterResources(requested.minResources(), clusterSpec.type(), clusterSpec.isExclusive(), nodeRepository)
+ ? new AllocatableClusterResources(requested.minResources(), clusterSpec, nodeRepository)
: new AllocatableClusterResources(nodes, nodeRepository, clusterSpec.isExclusive());
return within(Limits.of(requested), clusterSpec.isExclusive(), currentResources, firstDeployment);
}