aboutsummaryrefslogtreecommitdiffstats
path: root/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
diff options
context:
space:
mode:
Diffstat (limited to 'node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java50
1 files changed, 29 insertions, 21 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
index de132d53d63..4c5ace3d51a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
@@ -8,7 +8,6 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.applications.Application;
import com.yahoo.vespa.hosted.provision.applications.Cluster;
import com.yahoo.vespa.hosted.provision.provisioning.CapacityPolicies;
-import com.yahoo.vespa.hosted.provision.provisioning.AllocationParams;
import java.time.Clock;
import java.time.Duration;
@@ -47,8 +46,9 @@ public class ClusterModel {
// TODO: Measure this, and only take it into account with queries
private static final double fixedCpuCostFraction = 0.1;
- private final AllocationParams params;
+ private final NodeRepository nodeRepository;
private final Application application;
+ private final ClusterSpec clusterSpec;
private final Cluster cluster;
private final AllocatableResources current;
@@ -74,28 +74,31 @@ public class ClusterModel {
private Double maxQueryGrowthRate = null;
private OptionalDouble averageQueryRate = null;
- public ClusterModel(AllocationParams params,
+ public ClusterModel(NodeRepository nodeRepository,
Application application,
+ ClusterSpec clusterSpec,
Cluster cluster,
NodeList clusterNodes,
AllocatableResources current,
MetricsDb metricsDb,
Clock clock) {
- this.params = params;
+ this.nodeRepository = nodeRepository;
this.application = application;
+ this.clusterSpec = clusterSpec;
this.cluster = cluster;
this.nodes = clusterNodes;
this.current = current;
this.clock = clock;
- this.scalingDuration = cluster.scalingDuration(params.cluster());
- this.allocationDuration = cluster.allocationDuration(params.cluster());
+ this.scalingDuration = cluster.scalingDuration(clusterSpec);
+ this.allocationDuration = cluster.allocationDuration(clusterSpec);
this.clusterTimeseries = metricsDb.getClusterTimeseries(application.id(), cluster.id());
this.nodeTimeseries = new ClusterNodesTimeseries(scalingDuration(), cluster, nodes, metricsDb);
this.at = clock.instant();
}
- ClusterModel(AllocationParams params,
+ ClusterModel(NodeRepository nodeRepository,
Application application,
+ ClusterSpec clusterSpec,
Cluster cluster,
AllocatableResources current,
Clock clock,
@@ -103,8 +106,9 @@ public class ClusterModel {
Duration allocationDuration,
ClusterTimeseries clusterTimeseries,
ClusterNodesTimeseries nodeTimeseries) {
- this.params = params;
+ this.nodeRepository = nodeRepository;
this.application = application;
+ this.clusterSpec = clusterSpec;
this.cluster = cluster;
this.nodes = NodeList.of();
this.current = current;
@@ -118,7 +122,7 @@ public class ClusterModel {
}
public Application application() { return application; }
- public ClusterSpec clusterSpec() { return params.cluster(); }
+ public ClusterSpec clusterSpec() { return clusterSpec; }
public AllocatableResources current() { return current; }
private ClusterNodesTimeseries nodeTimeseries() { return nodeTimeseries; }
private ClusterTimeseries clusterTimeseries() { return clusterTimeseries; }
@@ -140,7 +144,7 @@ public class ClusterModel {
public Duration allocationDuration() { return allocationDuration; }
public boolean isContent() {
- return params.cluster().type().isContent();
+ return clusterSpec.type().isContent();
}
/** Returns the predicted duration of data redistribution in this cluster. */
@@ -165,7 +169,7 @@ public class ClusterModel {
}
public boolean isExclusive() {
- return params.exclusiveAllocation();
+ return nodeRepository.exclusiveAllocation(clusterSpec);
}
/** Returns the relative load adjustment that should be made to this cluster given available measurements. */
@@ -273,7 +277,7 @@ public class ClusterModel {
* cluster.bcpGroupInfo().growthRateHeadroom() * trafficShiftHeadroom();
double neededTotalVcpuPerGroup = cluster.bcpGroupInfo().cpuCostPerQuery() * targetQueryRateToHandle / groupCount() +
( 1 - cpu.queryFraction()) * cpu.idealLoad() *
- (params.cluster().type().isContainer() ? 1 : groupSize());
+ (clusterSpec.type().isContainer() ? 1 : groupSize());
// Max 1: Only use bcp group info if it indicates that we need to scale *up*
double cpuAdjustment = Math.max(1.0, neededTotalVcpuPerGroup / currentClusterTotalVcpuPerGroup);
return ideal.withCpu(ideal.cpu() / cpuAdjustment);
@@ -337,7 +341,7 @@ public class ClusterModel {
/** Returns the headroom for growth during organic traffic growth as a multiple of current resources. */
private double growthRateHeadroom() {
- if ( ! params.nodeRepository().zone().environment().isProduction()) return 1;
+ if ( ! nodeRepository.zone().environment().isProduction()) return 1;
double growthRateHeadroom = 1 + maxQueryGrowthRate() * scalingDuration().toMinutes();
// Cap headroom at 10% above the historical observed peak
if (queryFractionOfMax() != 0)
@@ -351,7 +355,7 @@ public class ClusterModel {
* as a multiple of current resources.
*/
private double trafficShiftHeadroom() {
- if ( ! params.nodeRepository().zone().environment().isProduction()) return 1;
+ if ( ! nodeRepository.zone().environment().isProduction()) return 1;
if (canRescaleWithinBcpDeadline()) return 1;
double trafficShiftHeadroom;
if (application.status().maxReadShare() == 0) // No traffic fraction data
@@ -387,7 +391,7 @@ public class ClusterModel {
OptionalDouble costPerQuery() {
if (averageQueryRate().isEmpty() || averageQueryRate().getAsDouble() == 0.0) return OptionalDouble.empty();
// TODO: Query rate should generally be sampled at the time where we see the peak resource usage
- int fanOut = params.cluster().type().isContainer() ? 1 : groupSize();
+ int fanOut = clusterSpec.type().isContainer() ? 1 : groupSize();
return OptionalDouble.of(peakLoad().cpu() * cpu.queryFraction() * fanOut * nodes.not().retired().first().get().resources().vcpu()
/ averageQueryRate().getAsDouble() / groupCount());
}
@@ -410,8 +414,8 @@ public class ClusterModel {
private class MemoryModel {
double idealLoad() {
- if (params.cluster().type().isContainer()) return idealContainerMemoryLoad;
- if (params.cluster().type() == ClusterSpec.Type.admin) return idealContainerMemoryLoad; // Not autoscaled, but ideal shown in console
+ if (clusterSpec.type().isContainer()) return idealContainerMemoryLoad;
+ if (clusterSpec.type() == ClusterSpec.Type.admin) return idealContainerMemoryLoad; // Not autoscaled, but ideal shown in console
return idealContentMemoryLoad;
}
@@ -428,12 +432,16 @@ public class ClusterModel {
double averageReal() {
if (nodes.isEmpty()) { // we're estimating
- var initialResources = new CapacityPolicies(params.nodeRepository()).specifyFully(params, cluster.minResources().nodeResources());
- return params.nodeRepository().resourcesCalculator().requestToReal(initialResources, params.exclusiveAllocation(), false).memoryGb();
+ var initialResources = new CapacityPolicies(nodeRepository).specifyFully(cluster.minResources().nodeResources(),
+ clusterSpec,
+ application.id());
+ return nodeRepository.resourcesCalculator().requestToReal(initialResources,
+ nodeRepository.exclusiveAllocation(clusterSpec),
+ false).memoryGb();
}
else {
return nodes.stream()
- .mapToDouble(node -> params.nodeRepository().resourcesCalculator().realResourcesOf(node, params.nodeRepository()).memoryGb())
+ .mapToDouble(node -> nodeRepository.resourcesCalculator().realResourcesOf(node, nodeRepository).memoryGb())
.average()
.getAsDouble();
}
@@ -446,7 +454,7 @@ public class ClusterModel {
double idealLoad() {
// Stateless clusters are not expected to consume more disk over time -
// if they do it is due to logs which will be rotated away right before the disk is full
- return params.cluster().isStateful() ? idealContentDiskLoad : idealContainerDiskLoad;
+ return clusterSpec.isStateful() ? idealContentDiskLoad : idealContainerDiskLoad;
}
}