diff options
author | Jon Bratseth <bratseth@gmail.com> | 2022-07-17 11:53:57 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2022-07-17 11:53:57 +0200 |
commit | 6b0773217a52659c8698076a5a57561d542f9bc0 (patch) | |
tree | 85c4b278e2b9418d7b0fde86a30e7178b69d96a7 | |
parent | 80d967ebd1e8b0639f975c75e4f03da5dec61ee3 (diff) |
Introduce fixture
9 files changed, 194 insertions, 95 deletions
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 7fa369da9c6..41fa9499353 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 @@ -67,7 +67,6 @@ public class AllocationOptimizer { limits, target, current, clusterModel)); var allocatableResources = AllocatableClusterResources.from(next, current.clusterSpec(), limits, hosts, nodeRepository); - if (allocatableResources.isEmpty()) continue; if (bestAllocation.isEmpty() || allocatableResources.get().preferableTo(bestAllocation.get())) bestAllocation = allocatableResources; 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 ed1fbcd3ff8..ac072639cfe 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 @@ -61,8 +61,8 @@ public class Autoscaler { private Advice autoscale(Application application, Cluster cluster, NodeList clusterNodes, Limits limits) { ClusterModel clusterModel = new ClusterModel(application, - cluster, clusterNodes.clusterSpec(), + cluster, clusterNodes, nodeRepository.metricsDb(), nodeRepository.clock()); 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 34e31671491..5b1ee6cc496 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 @@ -48,8 +48,8 @@ public class ClusterModel { private Double maxQueryGrowthRate = null; public ClusterModel(Application application, - Cluster cluster, ClusterSpec clusterSpec, + Cluster cluster, NodeList clusterNodes, MetricsDb metricsDb, Clock clock) { @@ -169,7 +169,6 @@ public class ClusterModel { // Assume we have missed timely recording completion if it is longer than 4 days totalDuration = totalDuration.plus(maximum(Duration.ofDays(4), event.duration().get())); } - if (completedEventCount == 0) { // Use defaults if (clusterSpec.isStateful()) return Duration.ofHours(12); return Duration.ofMinutes(10); @@ -210,13 +209,13 @@ public class ClusterModel { * as QuestDb is known to temporarily fail during reading of data. */ public static Optional<ClusterModel> create(Application application, - Cluster cluster, ClusterSpec clusterSpec, + Cluster cluster, NodeList clusterNodes, MetricsDb metricsDb, Clock clock) { try { - return Optional.of(new ClusterModel(application, cluster, clusterSpec, clusterNodes, metricsDb, clock)); + return Optional.of(new ClusterModel(application, clusterSpec, cluster, clusterNodes, metricsDb, clock)); } catch (Exception e) { log.log(Level.WARNING, "Failed creating a cluster model for " + application + " " + cluster, e); 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 64865c15529..4ffe04d748c 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 @@ -171,7 +171,7 @@ public class NodeRepositoryProvisioner implements Provisioner { firstDeployment // start at min, preserve current resources otherwise ? new AllocatableClusterResources(initialResourcesFrom(requested, clusterSpec, application.id()), clusterSpec, nodeRepository) : new AllocatableClusterResources(nodes.asList(), nodeRepository); - var clusterModel = new ClusterModel(application, cluster, clusterSpec, nodes, nodeRepository.metricsDb(), nodeRepository.clock()); + var clusterModel = new ClusterModel(application, clusterSpec, cluster, nodes, nodeRepository.metricsDb(), nodeRepository.clock()); return within(Limits.of(requested), currentResources, firstDeployment, clusterModel); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java index f0b8e77ee56..1c10de8498a 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java @@ -62,7 +62,7 @@ public class ApplicationSerializer { NodeList nodes = applicationNodes.not().retired().cluster(cluster.id()); if (nodes.isEmpty()) return; ClusterResources currentResources = nodes.toResources(); - Optional<ClusterModel> clusterModel = ClusterModel.create(application, cluster, nodes.clusterSpec(), nodes, metricsDb, nodeRepository.clock()); + Optional<ClusterModel> clusterModel = ClusterModel.create(application, nodes.clusterSpec(), cluster, nodes, metricsDb, nodeRepository.clock()); Cursor clusterObject = clustersObject.setObject(cluster.id().value()); clusterObject.setString("type", nodes.clusterSpec().type().name()); toSlime(cluster.minResources(), clusterObject.setObject("min")); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java index 667dffef2a6..bb441c6621c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java @@ -37,8 +37,8 @@ public class AutoscalingIntegrationTest { new MockHttpClient(tester.clock())); Autoscaler autoscaler = new Autoscaler(tester.nodeRepository()); - ApplicationId application1 = tester.applicationId("test1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "test"); + ApplicationId application1 = AutoscalingTester.applicationId("test1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "test"); Set<String> hostnames = tester.deploy(application1, cluster1, 2, 1, nodes) .stream().map(HostSpec::hostname) .collect(Collectors.toSet()); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java index d3142b3cc7f..273c909220b 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java @@ -44,8 +44,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(hostResources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); // deploy tester.deploy(application1, cluster1, 5, 1, hostResources); @@ -89,36 +89,30 @@ public class AutoscalingTest { tester.autoscale(application1, cluster1, capacity)); } + /** Using too many resources for a short period is proof we should scale up regardless of the time that takes. */ + @Test + public void test_autoscaling_up_is_fast_TODO() { + var fixture = AutoscalingTester.fixture().build(); + fixture.tester().clock().advance(Duration.ofDays(1)); // TODO: Remove the need for this + fixture.applyLoad(1.0, 1.0, 1.0, 120); // TODO: Make this low + fixture.tester().assertResources("Scaling up since resource usage is too high", + 10, 1, 9.4, 8.5, 92.6, + fixture.autoscale()); + } + /** We prefer fewer nodes for container clusters as (we assume) they all use the same disk and memory */ @Test public void test_autoscaling_single_container_group() { - NodeResources resources = new NodeResources(3, 100, 100, 1); - ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources(20, 1, new NodeResources(100, 1000, 1000, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); - - // deploy - tester.deploy(application1, cluster1, 5, 1, resources); - tester.addCpuMeasurements(0.25f, 1f, 120, application1); - tester.clock().advance(Duration.ofMinutes(-10 * 5)); - tester.addQueryRateMeasurements(application1, cluster1.id(), 10, t -> t == 0 ? 20.0 : 10.0); // Query traffic only - ClusterResources scaledResources = tester.assertResources("Scaling up since cpu usage is too high", - 7, 1, 2.5, 80.0, 50.5, - tester.autoscale(application1, cluster1, capacity)); - - tester.deploy(application1, cluster1, scaledResources); - tester.deactivateRetired(application1, cluster1, scaledResources); - - tester.addCpuMeasurements(0.1f, 1f, 120, application1); - tester.clock().advance(Duration.ofMinutes(-10 * 5)); - tester.addQueryRateMeasurements(application1, cluster1.id(), 10, t -> t == 0 ? 20.0 : 10.0); // Query traffic only - tester.assertResources("Scaling down since cpu usage has gone down", - 4, 1, 2.5, 68.6, 27.4, - tester.autoscale(application1, cluster1, capacity)); + var fixture = AutoscalingTester.fixture().clusterType(ClusterSpec.Type.container).build(); + fixture.applyCpuLoad(0.25f, 120); + ClusterResources scaledResources = fixture.tester().assertResources("Scaling up since cpu usage is too high", + 5, 1, 3.8, 8.0, 50.5, + fixture.autoscale()); + fixture.deploy(scaledResources); + fixture.applyCpuLoad(0.1f, 120); + fixture.tester().assertResources("Scaling down since cpu usage has gone down", + 4, 1, 2.5, 6.4, 25.5, + fixture.autoscale()); } @Test @@ -126,8 +120,8 @@ public class AutoscalingTest { NodeResources hostResources = new NodeResources(3, 100, 100, 1, NodeResources.DiskSpeed.slow); AutoscalingTester tester = new AutoscalingTester(hostResources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); // deploy with slow tester.deploy(application1, cluster1, 5, 1, hostResources); @@ -158,8 +152,8 @@ public class AutoscalingTest { NodeResources hostResources = new NodeResources(3, 100, 100, 1); AutoscalingTester tester = new AutoscalingTester(hostResources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); // Initial deployment NodeResources resources = new NodeResources(1, 10, 10, 1); @@ -192,8 +186,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(hostResources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 5, 1, @@ -214,8 +208,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 5, 1, resources); @@ -233,8 +227,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(hostResources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); NodeResources defaultResources = new CapacityPolicies(tester.nodeRepository()).defaultNodeResources(cluster1, application1, false); @@ -261,8 +255,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(hostResources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 5, 5, new NodeResources(3.0, 10, 10, 1)); @@ -282,8 +276,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(resources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 5, 1, resources); @@ -308,8 +302,8 @@ public class AutoscalingTest { tester.provisioning().makeReadyNodes(5, remoteFlavor.name(), NodeType.host, 8); tester.provisioning().activateTenantHosts(); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 3, 1, min.nodeResources()); @@ -331,8 +325,8 @@ public class AutoscalingTest { ClusterResources max = min; AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 5, 1, resources); @@ -352,8 +346,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 2, 1, resources); @@ -370,8 +364,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 2, 1, resources); @@ -388,8 +382,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 5, 5, resources); @@ -409,8 +403,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 6, 2, resources); @@ -433,8 +427,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); // deploy tester.deploy(application1, cluster1, 6, 2, resources); @@ -456,8 +450,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(hostResources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); // deploy tester.deploy(application1, cluster1, 6, 2, new NodeResources(10, 100, 100, 1)); @@ -478,8 +472,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(hostResources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); // deploy tester.deploy(application1, cluster1, 6, 1, hostResources.withVcpu(hostResources.vcpu() / 2)); @@ -499,8 +493,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(hostResources); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); tester.deploy(application1, cluster1, 6, 1, hostResources.withVcpu(hostResources.vcpu() / 2)); @@ -532,8 +526,8 @@ public class AutoscalingTest { hostResources, new OnlySubtractingWhenForecastingCalculator(0)); - ApplicationId application1 = tester.applicationId("app1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("app1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); tester.deploy(application1, cluster1, min); tester.addMeasurements(1.0f, 1.0f, 0.7f, 0, 1000, application1); @@ -549,8 +543,8 @@ public class AutoscalingTest { hostResources, new OnlySubtractingWhenForecastingCalculator(15)); - ApplicationId application1 = tester.applicationId("app1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("app1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); tester.deploy(application1, cluster1, min); tester.addMeasurements(1.0f, 1.0f, 0.7f, 0, 1000, application1); @@ -579,8 +573,8 @@ public class AutoscalingTest { Environment.prod, RegionName.from("us-east")), flavors); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); // deploy (Why 103 Gb memory? See AutoscalingTester.MockHostResourcesCalculator tester.deploy(application1, cluster1, 5, 1, new NodeResources(3, 103, 100, 1)); @@ -611,8 +605,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); tester.deploy(application1, cluster1, 5, 1, resources); tester.addQueryRateMeasurements(application1, cluster1.id(), 100, t -> t == 0 ? 20.0 : 10.0); // Query traffic only @@ -645,8 +639,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(maxResources.withVcpu(maxResources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); tester.deploy(application1, cluster1, 5, 1, midResources); Duration timeAdded = tester.addQueryRateMeasurements(application1, cluster1.id(), 100, t -> t == 0 ? 20.0 : 10.0); @@ -691,8 +685,8 @@ public class AutoscalingTest { var capacity = Capacity.from(min, max); AutoscalingTester tester = new AutoscalingTester(maxResources.withVcpu(maxResources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); tester.deploy(application1, cluster1, 5, 1, midResources); tester.addCpuMeasurements(0.4f, 1f, 120, application1); @@ -744,8 +738,8 @@ public class AutoscalingTest { Capacity capacity = Capacity.from(min, max, false, true); AutoscalingTester tester = new AutoscalingTester(Environment.dev, resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); tester.deploy(application1, cluster1, capacity); tester.addQueryRateMeasurements(application1, cluster1.id(), @@ -764,8 +758,8 @@ public class AutoscalingTest { Capacity capacity = Capacity.from(min, max, true, true); AutoscalingTester tester = new AutoscalingTester(Environment.dev, resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); tester.deploy(application1, cluster1, capacity); tester.addQueryRateMeasurements(application1, cluster1.id(), @@ -785,8 +779,8 @@ public class AutoscalingTest { AutoscalingTester tester = new AutoscalingTester(Environment.dev, new NodeResources(10, 16, 100, 2)); - ApplicationId application1 = tester.applicationId("application1"); - ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + ApplicationId application1 = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); tester.deploy(application1, cluster1, capacity); tester.addQueryRateMeasurements(application1, cluster1.id(), diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java index f860b3e5d81..862eb744162 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java @@ -91,13 +91,15 @@ class AutoscalingTester { capacityPolicies = new CapacityPolicies(provisioningTester.nodeRepository()); } + public static Fixture.Builder fixture() { return new Fixture.Builder(); } + public ProvisioningTester provisioning() { return provisioningTester; } - public ApplicationId applicationId(String applicationName) { + public static ApplicationId applicationId(String applicationName) { return ApplicationId.from("tenant1", applicationName, "instance1"); } - public ClusterSpec clusterSpec(ClusterSpec.Type type, String clusterId) { + public static ClusterSpec clusterSpec(ClusterSpec.Type type, String clusterId) { return ClusterSpec.request(type, ClusterSpec.Id.from(clusterId)).vespaVersion("7").build(); } @@ -128,7 +130,7 @@ class AutoscalingTester { } public void deactivateRetired(ApplicationId application, ClusterSpec cluster, ClusterResources resources) { - try (Mutex lock = nodeRepository().nodes().lock(application)){ + try (Mutex lock = nodeRepository().nodes().lock(application)) { for (Node node : nodeRepository().nodes().list(Node.State.active).owner(application)) { if (node.allocation().get().membership().retired()) nodeRepository().nodes().write(node.with(node.allocation().get().removable(true, true)), lock); @@ -137,6 +139,16 @@ class AutoscalingTester { deploy(application, cluster, resources); } + public ClusterModel clusterModel(ApplicationId applicationId, ClusterSpec clusterSpec) { + var application = nodeRepository().applications().get(applicationId).get(); + return new ClusterModel(application, + clusterSpec, + application.cluster(clusterSpec.id()).get(), + nodeRepository().nodes().list(Node.State.active).cluster(clusterSpec.id()), + nodeRepository().metricsDb(), + nodeRepository().clock()); + } + /** * Adds measurements with the given resource value and ideal values for the other resources, * scaled to take one node redundancy into account. @@ -236,6 +248,10 @@ class AutoscalingTester { } } + public void addMeasurements(float cpu, float memory, float disk, int count, ApplicationId applicationId) { + addMeasurements(cpu, memory, disk, 0, true, true, count, applicationId); + } + public void addMeasurements(float cpu, float memory, float disk, int generation, int count, ApplicationId applicationId) { addMeasurements(cpu, memory, disk, generation, true, true, count, applicationId); } @@ -304,13 +320,21 @@ class AutoscalingTester { ClusterSpec.Id cluster, int measurements, IntFunction<Double> queryRate) { + return addQueryRateMeasurements(application, cluster, measurements, Duration.ofMinutes(5), queryRate); + } + + public Duration addQueryRateMeasurements(ApplicationId application, + ClusterSpec.Id cluster, + int measurements, + Duration samplingInterval, + IntFunction<Double> queryRate) { Instant initialTime = clock().instant(); for (int i = 0; i < measurements; i++) { nodeMetricsDb().addClusterMetrics(application, Map.of(cluster, new ClusterMetricSnapshot(clock().instant(), queryRate.apply(i), 0.0))); - clock().advance(Duration.ofMinutes(5)); + clock().advance(samplingInterval); } return Duration.between(initialTime, clock().instant()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Fixture.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Fixture.java new file mode 100644 index 00000000000..416f61d62d3 --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Fixture.java @@ -0,0 +1,83 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.provision.autoscale; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Capacity; +import com.yahoo.config.provision.ClusterResources; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.NodeResources; + +import java.time.Duration; + +/** + * Fixture for autoscaling tests. + * + * @author bratseth + */ +public class Fixture { + + final AutoscalingTester tester; + final ApplicationId application; + final ClusterSpec cluster; + final Capacity capacity; + + public Fixture(Fixture.Builder builder) { + application = builder.application; + cluster = builder.cluster; + capacity = Capacity.from(builder.min, builder.max); + tester = new AutoscalingTester(builder.hostResources); + tester.deploy(builder.application, builder.cluster, 5, 1, builder.nodeResources); + } + + public AutoscalingTester tester() { return tester; } + + public Autoscaler.Advice autoscale() { + return tester.autoscale(application, cluster, capacity); + } + + public void deploy(ClusterResources resources) { + tester.deploy(application, cluster, resources); + } + + public void deactivateRetired(ClusterResources resources) { + tester.deactivateRetired(application, cluster, resources); + } + + public void applyLoad(double cpuLoad, double memoryLoad, double diskLoad, int measurements) { + Duration samplingInterval = Duration.ofSeconds(150L); // in addCpuMeasurements + tester().addMeasurements((float)cpuLoad, (float)memoryLoad, (float)diskLoad, measurements, application); + tester().clock().advance(samplingInterval.negated().multipliedBy(measurements)); + tester().addQueryRateMeasurements(application, cluster.id(), measurements, samplingInterval, t -> t == 0 ? 20.0 : 10.0); // Query traffic only + } + + public void applyCpuLoad(double cpuLoad, int measurements) { + Duration samplingInterval = Duration.ofSeconds(150L); // in addCpuMeasurements + tester().addCpuMeasurements((float)cpuLoad, 1.0f, measurements, application); + tester().clock().advance(samplingInterval.negated().multipliedBy(measurements)); + tester().addQueryRateMeasurements(application, cluster.id(), measurements, samplingInterval, t -> t == 0 ? 20.0 : 10.0); // Query traffic only + } + + public static class Builder { + + NodeResources hostResources = new NodeResources(100, 100, 100, 1); + NodeResources nodeResources = new NodeResources(3, 10, 100, 1); + ClusterResources min = new ClusterResources(2, 1, + new NodeResources(1, 1, 1, 1, NodeResources.DiskSpeed.any)); + ClusterResources max = new ClusterResources(20, 1, + new NodeResources(100, 1000, 1000, 1, NodeResources.DiskSpeed.any)); + + ApplicationId application = AutoscalingTester.applicationId("application1"); + ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("cluster1")).vespaVersion("7").build(); + + public Fixture.Builder clusterType(ClusterSpec.Type type) { + cluster = ClusterSpec.request(type, cluster.id()).vespaVersion("7").build(); + return this; + } + + public Fixture build() { + return new Fixture(this); + } + + } + +} |