From 6b0773217a52659c8698076a5a57561d542f9bc0 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 11:53:57 +0200 Subject: Introduce fixture --- .../provision/autoscale/AllocationOptimizer.java | 1 - .../hosted/provision/autoscale/Autoscaler.java | 2 +- .../hosted/provision/autoscale/ClusterModel.java | 7 +- .../provisioning/NodeRepositoryProvisioner.java | 2 +- .../provision/restapi/ApplicationSerializer.java | 2 +- .../autoscale/AutoscalingIntegrationTest.java | 4 +- .../provision/autoscale/AutoscalingTest.java | 156 ++++++++++----------- .../provision/autoscale/AutoscalingTester.java | 32 ++++- .../vespa/hosted/provision/autoscale/Fixture.java | 83 +++++++++++ 9 files changed, 194 insertions(+), 95 deletions(-) create mode 100644 node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Fixture.java 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 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.create(application, cluster, nodes.clusterSpec(), nodes, metricsDb, nodeRepository.clock()); + Optional 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 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 queryRate) { + return addQueryRateMeasurements(application, cluster, measurements, Duration.ofMinutes(5), queryRate); + } + + public Duration addQueryRateMeasurements(ApplicationId application, + ClusterSpec.Id cluster, + int measurements, + Duration samplingInterval, + IntFunction 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); + } + + } + +} -- cgit v1.2.3 From 3a24aefe5163d61b406e8aeaef69f68f4bf0b937 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 12:07:53 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 64 ++++++++-------------- 1 file changed, 22 insertions(+), 42 deletions(-) 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 273c909220b..f3af5016697 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 @@ -36,57 +36,37 @@ public class AutoscalingTest { @Test public void test_autoscaling_single_content_group() { - NodeResources hostResources = new NodeResources(3, 100, 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)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(hostResources); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + var fixture = AutoscalingTester.fixture().build(); - // deploy - tester.deploy(application1, cluster1, 5, 1, hostResources); + fixture.tester().clock().advance(Duration.ofDays(1)); + assertTrue("No measurements -> No change", fixture.autoscale().isEmpty()); - tester.clock().advance(Duration.ofDays(1)); - assertTrue("No measurements -> No change", tester.autoscale(application1, cluster1, capacity).isEmpty()); + fixture.applyCpuLoad(0.7f, 59); + assertTrue("Too few measurements -> No change", fixture.autoscale().isEmpty()); - tester.addCpuMeasurements(0.25f, 1f, 59, application1); - assertTrue("Too few measurements -> No change", tester.autoscale(application1, cluster1, capacity).isEmpty()); + fixture.tester().clock().advance(Duration.ofDays(1)); + fixture.applyCpuLoad(0.7f, 120); + ClusterResources scaledResources = fixture.tester().assertResources("Scaling up since resource usage is too high", + 9, 1, 2.8, 5.0, 50.0, + fixture.autoscale()); - tester.clock().advance(Duration.ofDays(1)); - 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 resource usage is too high", - 15, 1, 1.2, 28.6, 28.6, - tester.autoscale(application1, cluster1, capacity)); + fixture.deploy(scaledResources); + assertTrue("Cluster in flux -> No further change", fixture.autoscale().isEmpty()); - tester.deploy(application1, cluster1, scaledResources); - assertTrue("Cluster in flux -> No further change", tester.autoscale(application1, cluster1, capacity).isEmpty()); + fixture.deactivateRetired(scaledResources); - tester.deactivateRetired(application1, cluster1, scaledResources); - - tester.clock().advance(Duration.ofDays(2)); - tester.addCpuMeasurements(0.8f, 1f, 3, application1); - tester.clock().advance(Duration.ofMinutes(-10 * 5)); - tester.addQueryRateMeasurements(application1, cluster1.id(), 10, t -> t == 0 ? 20.0 : 10.0); // Query traffic only + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyCpuLoad(0.8f, 3); assertTrue("Load change is large, but insufficient measurements for new config -> No change", - tester.autoscale(application1, cluster1, capacity).isEmpty()); + fixture.autoscale().isEmpty()); - tester.addCpuMeasurements(0.19f, 1f, 100, application1); - tester.clock().advance(Duration.ofMinutes(-10 * 5)); - tester.addQueryRateMeasurements(application1, cluster1.id(), 10, t -> t == 0 ? 20.0 : 10.0); // Query traffic only - assertEquals("Load change is small -> No change", Optional.empty(), tester.autoscale(application1, cluster1, capacity).target()); + fixture.applyCpuLoad(0.19f, 100); + assertEquals("Load change is small -> No change", Optional.empty(), fixture.autoscale().target()); - 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 to minimum since usage has gone down significantly", - 7, 1, 1.0, 66.7, 66.7, - tester.autoscale(application1, cluster1, capacity)); + fixture.applyCpuLoad(0.1f, 120); + fixture.tester().assertResources("Scaling cpu down since usage has gone down significantly", + 9, 1, 1.0, 5.0, 50.0, + fixture.autoscale()); } /** Using too many resources for a short period is proof we should scale up regardless of the time that takes. */ -- cgit v1.2.3 From 7d1955dbbe90db24537f566bd1c503c8454d31fc Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 14:30:48 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 79 ++++++++++------------ .../provision/autoscale/AutoscalingTester.java | 6 +- .../vespa/hosted/provision/autoscale/Fixture.java | 61 +++++++++++++---- 3 files changed, 88 insertions(+), 58 deletions(-) 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 f3af5016697..e36091332be 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 @@ -50,10 +50,10 @@ public class AutoscalingTest { 9, 1, 2.8, 5.0, 50.0, fixture.autoscale()); - fixture.deploy(scaledResources); + fixture.deploy(Capacity.from(scaledResources)); assertTrue("Cluster in flux -> No further change", fixture.autoscale().isEmpty()); - fixture.deactivateRetired(scaledResources); + fixture.deactivateRetired(Capacity.from(scaledResources)); fixture.tester().clock().advance(Duration.ofDays(2)); fixture.applyCpuLoad(0.8f, 3); @@ -88,7 +88,7 @@ public class AutoscalingTest { 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.deploy(Capacity.from(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, @@ -97,65 +97,56 @@ public class AutoscalingTest { @Test public void autoscaling_handles_disk_setting_changes() { - NodeResources hostResources = new NodeResources(3, 100, 100, 1, NodeResources.DiskSpeed.slow); - AutoscalingTester tester = new AutoscalingTester(hostResources); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); - - // deploy with slow - tester.deploy(application1, cluster1, 5, 1, hostResources); - assertTrue(tester.nodeRepository().nodes().list().owner(application1).stream() + var resources = new NodeResources(3, 100, 100, 1, NodeResources.DiskSpeed.slow); + var fixture = AutoscalingTester.fixture() + .hostResources(resources) + .initialResources(Optional.of(new ClusterResources(5, 1, resources))) + .capacity(Capacity.from(new ClusterResources(5, 1, resources))) + .build(); + + assertTrue(fixture.tester().nodeRepository().nodes().list().owner(fixture.application).stream() .allMatch(n -> n.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.slow)); - tester.clock().advance(Duration.ofDays(2)); - tester.addQueryRateMeasurements(application1, cluster1.id(), 100, t -> t == 0 ? 20.0 : 10.0); // Query traffic only - tester.addCpuMeasurements(0.25f, 1f, 120, application1); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyCpuLoad(0.25, 120); + // Changing min and max from slow to any 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)); var capacity = Capacity.from(min, max); - ClusterResources scaledResources = tester.assertResources("Scaling up since resource usage is too high", - 14, 1, 1.4, 30.8, 30.8, - tester.autoscale(application1, cluster1, capacity)); - assertEquals("Disk speed from min/max is used", + ClusterResources scaledResources = fixture.tester().assertResources("Scaling up", + 14, 1, 1.4, 30.8, 30.8, + fixture.autoscale(capacity)); + assertEquals("Disk speed from new capacity is used", NodeResources.DiskSpeed.any, scaledResources.nodeResources().diskSpeed()); - tester.deploy(application1, cluster1, scaledResources); - assertTrue(tester.nodeRepository().nodes().list().owner(application1).stream() - .allMatch(n -> n.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.any)); + fixture.deploy(Capacity.from(scaledResources)); + assertTrue(fixture.nodes().stream() + .allMatch(n -> n.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.any)); } @Test public void autoscaling_target_preserves_any() { - NodeResources hostResources = new NodeResources(3, 100, 100, 1); - AutoscalingTester tester = new AutoscalingTester(hostResources); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); - - // Initial deployment NodeResources resources = new NodeResources(1, 10, 10, 1); - var min = new ClusterResources( 2, 1, resources.with(NodeResources.DiskSpeed.any)); - var max = new ClusterResources( 10, 1, resources.with(NodeResources.DiskSpeed.any)); - var capacity = Capacity.from(min, max); - tester.deploy(application1, cluster1, Capacity.from(min, max)); + var capacity = Capacity.from(new ClusterResources( 2, 1, resources.with(NodeResources.DiskSpeed.any)), + new ClusterResources( 10, 1, resources.with(NodeResources.DiskSpeed.any))); + + var fixture = AutoscalingTester.fixture() + .capacity(capacity) + .initialResources(Optional.empty()) + .build(); // Redeployment without target: Uses current resource numbers with *requested* non-numbers (i.e disk-speed any) - assertTrue(tester.nodeRepository().applications().get(application1).get().cluster(cluster1.id()).get().targetResources().isEmpty()); - tester.deploy(application1, cluster1, Capacity.from(min, max)); - assertEquals(NodeResources.DiskSpeed.any, - tester.nodeRepository().nodes().list().owner(application1).cluster(cluster1.id()).first().get() - .allocation().get().requestedResources().diskSpeed()); + assertTrue(fixture.tester().nodeRepository().applications().get(fixture.application).get().cluster(fixture.cluster.id()).get().targetResources().isEmpty()); + fixture.deploy(); + assertEquals(NodeResources.DiskSpeed.any, fixture.nodes().first().get().allocation().get().requestedResources().diskSpeed()); // Autoscaling: Uses disk-speed any as well - tester.clock().advance(Duration.ofDays(2)); - tester.addCpuMeasurements(0.8f, 1f, 120, application1); - Autoscaler.Advice advice = tester.autoscale(application1, cluster1, capacity); - assertEquals(NodeResources.DiskSpeed.any, advice.target().get().nodeResources().diskSpeed()); - - + fixture.deactivateRetired(capacity); + fixture.tester().clock().advance(Duration.ofDays(1)); + fixture.applyCpuLoad(0.8, 120); + assertEquals(NodeResources.DiskSpeed.any, fixture.autoscale(capacity).target().get().nodeResources().diskSpeed()); } @Test 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 862eb744162..e08444c6edb 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 @@ -130,13 +130,17 @@ class AutoscalingTester { } public void deactivateRetired(ApplicationId application, ClusterSpec cluster, ClusterResources resources) { + deactivateRetired(application, cluster, Capacity.from(resources)); + } + + public void deactivateRetired(ApplicationId application, ClusterSpec cluster, Capacity capacity) { 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); } } - deploy(application, cluster, resources); + deploy(application, cluster, capacity); } public ClusterModel clusterModel(ApplicationId applicationId, ClusterSpec clusterSpec) { 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 index 416f61d62d3..371cbe25e1b 100644 --- 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 @@ -6,8 +6,10 @@ 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 com.yahoo.vespa.hosted.provision.NodeList; import java.time.Duration; +import java.util.Optional; /** * Fixture for autoscaling tests. @@ -21,26 +23,44 @@ public class Fixture { final ClusterSpec cluster; final Capacity capacity; - public Fixture(Fixture.Builder builder) { + public Fixture(Fixture.Builder builder, Optional initialResources) { application = builder.application; cluster = builder.cluster; - capacity = Capacity.from(builder.min, builder.max); + capacity = builder.capacity; tester = new AutoscalingTester(builder.hostResources); - tester.deploy(builder.application, builder.cluster, 5, 1, builder.nodeResources); + var deployCapacity = initialResources.isPresent() ? Capacity.from(initialResources.get()) : capacity; + tester.deploy(builder.application, builder.cluster, deployCapacity); } public AutoscalingTester tester() { return tester; } + /** Autoscale within the deployed capacity of this. */ public Autoscaler.Advice autoscale() { + return autoscale(capacity); + } + + /** Autoscale within the given capacity. */ + public Autoscaler.Advice autoscale(Capacity capacity) { return tester.autoscale(application, cluster, capacity); } - public void deploy(ClusterResources resources) { - tester.deploy(application, cluster, resources); + /** Redeploy with the deployed capacity of this. */ + public void deploy() { + deploy(capacity); + } + + /** Redeploy with the given capacity. */ + public void deploy(Capacity capacity) { + tester.deploy(application, cluster, capacity); } - public void deactivateRetired(ClusterResources resources) { - tester.deactivateRetired(application, cluster, resources); + /** Returns the nodes allocated to the fixture application cluster */ + public NodeList nodes() { + return tester.nodeRepository().nodes().list().owner(application).cluster(cluster.id()); + } + + public void deactivateRetired(Capacity capacity) { + tester.deactivateRetired(application, cluster, capacity); } public void applyLoad(double cpuLoad, double memoryLoad, double diskLoad, int measurements) { @@ -60,11 +80,11 @@ public class Fixture { 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)); + Optional initialResources = Optional.of(new ClusterResources(5, 1, new NodeResources(3, 10, 100, 1))); + Capacity capacity = Capacity.from(new ClusterResources(2, 1, + new NodeResources(1, 1, 1, 1, NodeResources.DiskSpeed.any)), + 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(); @@ -74,8 +94,23 @@ public class Fixture { return this; } + public Fixture.Builder hostResources(NodeResources hostResources) { + this.hostResources = hostResources; + return this; + } + + public Fixture.Builder initialResources(Optional initialResources) { + this.initialResources = initialResources; + return this; + } + + public Fixture.Builder capacity(Capacity capacity) { + this.capacity = capacity; + return this; + } + public Fixture build() { - return new Fixture(this); + return new Fixture(this, initialResources); } } -- cgit v1.2.3 From 3c8c5ca0bc5746510d4e6d337499fec71b9660ae Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 17:56:18 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 41 ++++++++-------------- 1 file changed, 14 insertions(+), 27 deletions(-) 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 e36091332be..8f168bc2232 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 @@ -131,7 +131,6 @@ public class AutoscalingTest { NodeResources resources = new NodeResources(1, 10, 10, 1); var capacity = Capacity.from(new ClusterResources( 2, 1, resources.with(NodeResources.DiskSpeed.any)), new ClusterResources( 10, 1, resources.with(NodeResources.DiskSpeed.any))); - var fixture = AutoscalingTester.fixture() .capacity(capacity) .initialResources(Optional.empty()) @@ -151,43 +150,31 @@ public class AutoscalingTest { @Test public void autoscaling_respects_upper_limit() { - NodeResources hostResources = new NodeResources(6, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources( 6, 1, new NodeResources(2.4, 78, 79, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(hostResources); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + var fixture = AutoscalingTester.fixture() + .initialResources(Optional.of(new ClusterResources(5, 1, new NodeResources(1.9, 70, 70, 1) ))) + .capacity(Capacity.from(min, max)).build(); - // deploy - tester.deploy(application1, cluster1, 5, 1, - new NodeResources(1.9, 70, 70, 1)); - tester.addMeasurements(0.25f, 0.95f, 0.95f, 0, 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 up to limit since resource usage is too high", - 6, 1, 2.4, 78.0, 70.0, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().clock().advance(Duration.ofDays(1)); + fixture.applyLoad(0.25, 0.95, 0.95, 120); + fixture.tester().assertResources("Scaling up to limit since resource usage is too high", + 6, 1, 2.4, 78.0, 79.0, + fixture.autoscale()); } @Test public void autoscaling_respects_lower_limit() { - NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 4, 1, new NodeResources(1.8, 7.4, 8.5, 1)); ClusterResources max = new ClusterResources( 6, 1, new NodeResources(2.4, 78, 79, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + var fixture = AutoscalingTester.fixture().capacity(Capacity.from(min, max)).build(); // deploy - tester.deploy(application1, cluster1, 5, 1, resources); - tester.addMeasurements(0.05f, 0.05f, 0.05f, 0, 120, application1); - tester.assertResources("Scaling down to limit since resource usage is low", - 4, 1, 1.8, 7.7, 10.0, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyLoad(0.05f, 0.05f, 0.05f, 120); + fixture.tester().assertResources("Scaling down to limit since resource usage is low", + 4, 1, 1.8, 7.4, 13.9, + fixture.autoscale()); } @Test -- cgit v1.2.3 From ded8b324d4ad1e00e049bf9f1791f66019dad061 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 18:39:32 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 69 ++++++++++------------ 1 file changed, 30 insertions(+), 39 deletions(-) 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 8f168bc2232..6cba93d084d 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 @@ -150,10 +150,11 @@ public class AutoscalingTest { @Test public void autoscaling_respects_upper_limit() { - ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources( 6, 1, new NodeResources(2.4, 78, 79, 1)); + var min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); + var now = new ClusterResources(5, 1, new NodeResources(1.9, 70, 70, 1)); + var max = new ClusterResources( 6, 1, new NodeResources(2.4, 78, 79, 1)); var fixture = AutoscalingTester.fixture() - .initialResources(Optional.of(new ClusterResources(5, 1, new NodeResources(1.9, 70, 70, 1) ))) + .initialResources(Optional.of(now)) .capacity(Capacity.from(min, max)).build(); fixture.tester().clock().advance(Duration.ofDays(1)); @@ -179,51 +180,41 @@ public class AutoscalingTest { @Test public void autoscaling_with_unspecified_resources_use_defaults() { - NodeResources hostResources = new NodeResources(6, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, NodeResources.unspecified()); ClusterResources max = new ClusterResources( 6, 1, NodeResources.unspecified()); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(hostResources); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + var fixture = AutoscalingTester.fixture() + .initialResources(Optional.empty()) + .capacity(Capacity.from(min, max)) + .build(); NodeResources defaultResources = - new CapacityPolicies(tester.nodeRepository()).defaultNodeResources(cluster1, application1, false); + new CapacityPolicies(fixture.tester().nodeRepository()).defaultNodeResources(fixture.cluster, fixture.application, false); - // deploy - tester.deploy(application1, cluster1, Capacity.from(min, max)); - tester.assertResources("Min number of nodes and default resources", - 2, 1, defaultResources, - tester.nodeRepository().nodes().list().owner(application1).toResources()); - tester.addMeasurements(0.25f, 0.95f, 0.95f, 0, 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 up to limit since resource usage is too high", - 4, 1, - defaultResources.vcpu(), defaultResources.memoryGb(), defaultResources.diskGb(), - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().assertResources("Min number of nodes and default resources", + 2, 1, defaultResources, + fixture.nodes().toResources()); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyLoad(0.25, 0.95, 0.95, 120); + fixture.tester().assertResources("Scaling up", + 5, 1, + defaultResources.vcpu(), defaultResources.memoryGb(), defaultResources.diskGb(), + fixture.autoscale()); } @Test public void autoscaling_respects_group_limit() { - NodeResources hostResources = new NodeResources(30.0, 100, 100, 1); - ClusterResources min = new ClusterResources( 2, 2, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources(18, 6, new NodeResources(100, 1000, 1000, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(hostResources); - - 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)); - tester.addCpuMeasurements( 0.3f, 1f, 240, 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 up since resource usage is too high", - 6, 6, 3.6, 8.0, 10.0, - tester.autoscale(application1, cluster1, capacity)); + var min = new ClusterResources( 2, 2, new NodeResources(1, 1, 1, 1)); + var now = new ClusterResources(5, 5, new NodeResources(3.0, 10, 10, 1)); + var max = new ClusterResources(18, 6, new NodeResources(100, 1000, 1000, 1)); + var fixture = AutoscalingTester.fixture() + .initialResources(Optional.of(now)) + .capacity(Capacity.from(min, max)) + .build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyCpuLoad(0.3, 240); + fixture.tester().assertResources("Scaling up", + 6, 6, 3.8, 8.0, 10.0, + fixture.autoscale()); } @Test -- cgit v1.2.3 From f4e6dd30c35f4ed2ffd8f115992de7c442888074 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 18:43:28 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 23 ++++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) 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 6cba93d084d..6a585b52ee4 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 @@ -166,8 +166,8 @@ public class AutoscalingTest { @Test public void autoscaling_respects_lower_limit() { - ClusterResources min = new ClusterResources( 4, 1, new NodeResources(1.8, 7.4, 8.5, 1)); - ClusterResources max = new ClusterResources( 6, 1, new NodeResources(2.4, 78, 79, 1)); + var min = new ClusterResources( 4, 1, new NodeResources(1.8, 7.4, 8.5, 1)); + var max = new ClusterResources( 6, 1, new NodeResources(2.4, 78, 79, 1)); var fixture = AutoscalingTester.fixture().capacity(Capacity.from(min, max)).build(); // deploy @@ -180,8 +180,8 @@ public class AutoscalingTest { @Test public void autoscaling_with_unspecified_resources_use_defaults() { - ClusterResources min = new ClusterResources( 2, 1, NodeResources.unspecified()); - ClusterResources max = new ClusterResources( 6, 1, NodeResources.unspecified()); + var min = new ClusterResources( 2, 1, NodeResources.unspecified()); + var max = new ClusterResources( 6, 1, NodeResources.unspecified()); var fixture = AutoscalingTester.fixture() .initialResources(Optional.empty()) .capacity(Capacity.from(min, max)) @@ -219,20 +219,13 @@ public class AutoscalingTest { @Test public void test_autoscaling_limits_when_min_equals_max() { - NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); - ClusterResources max = min; - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(resources); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + var fixture = AutoscalingTester.fixture().capacity(Capacity.from(min, min)).build(); // deploy - tester.deploy(application1, cluster1, 5, 1, resources); - tester.clock().advance(Duration.ofDays(1)); - tester.addCpuMeasurements(0.25f, 1f, 120, application1); - assertTrue(tester.autoscale(application1, cluster1, capacity).isEmpty()); + fixture.tester().clock().advance(Duration.ofDays(1)); + fixture.applyCpuLoad(0.25, 120); + assertTrue(fixture.autoscale().isEmpty()); } @Test -- cgit v1.2.3 From 7308d9f8edb394c51703bc164f4e62bb5c638f82 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 18:59:57 +0200 Subject: Use fixture --- .../hosted/provision/autoscale/AutoscalingTest.java | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) 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 6a585b52ee4..e2e18a2da43 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 @@ -262,22 +262,13 @@ public class AutoscalingTest { @Test public void suggestions_ignores_limits() { - NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); - ClusterResources max = min; - AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.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 - tester.assertResources("Scaling up since resource usage is too high", - 7, 1, 2.5, 80.0, 50.5, - tester.suggest(application1, cluster1.id(), min, max)); + var fixture = AutoscalingTester.fixture().capacity(Capacity.from(min, min)).build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyCpuLoad(1.0, 120); + fixture.tester().assertResources("Scaling up ", + 8, 1, 9.3, 5.7, 57.1, + fixture.tester().suggest(fixture.application, fixture.cluster.id(), min, min)); } @Test -- cgit v1.2.3 From 7896ac687243a3ce9953f9ea952dbd5ede300eba Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 19:29:40 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 40 ++++++---------------- .../vespa/hosted/provision/autoscale/Fixture.java | 11 ++++-- 2 files changed, 20 insertions(+), 31 deletions(-) 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 e2e18a2da43..b8fcb3a3660 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 @@ -266,45 +266,27 @@ public class AutoscalingTest { var fixture = AutoscalingTester.fixture().capacity(Capacity.from(min, min)).build(); fixture.tester().clock().advance(Duration.ofDays(2)); fixture.applyCpuLoad(1.0, 120); - fixture.tester().assertResources("Scaling up ", + fixture.tester().assertResources("Suggesting above capacity limit", 8, 1, 9.3, 5.7, 57.1, fixture.tester().suggest(fixture.application, fixture.cluster.id(), min, min)); } @Test public void not_using_out_of_service_measurements() { - NodeResources resources = new NodeResources(3, 100, 100, 1); - ClusterResources min = new ClusterResources(2, 1, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources(5, 1, new NodeResources(100, 1000, 1000, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); - - // deploy - tester.deploy(application1, cluster1, 2, 1, resources); - tester.addMeasurements(0.5f, 0.6f, 0.7f, 1, false, true, 120, application1); - assertTrue("Not scaling up since nodes were measured while cluster was unstable", - tester.autoscale(application1, cluster1, capacity).isEmpty()); + var fixture = AutoscalingTester.fixture().build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyLoad(0.9, 0.6, 0.7, 1, false, true, 120); + assertTrue("Not scaling up since nodes were measured while cluster was out of service", + fixture.autoscale().isEmpty()); } @Test public void not_using_unstable_measurements() { - NodeResources resources = new NodeResources(3, 100, 100, 1); - ClusterResources min = new ClusterResources(2, 1, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources(5, 1, new NodeResources(100, 1000, 1000, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); - - // deploy - tester.deploy(application1, cluster1, 2, 1, resources); - tester.addMeasurements(0.5f, 0.6f, 0.7f, 1, true, false, 120, application1); - assertTrue("Not scaling up since nodes were measured while cluster was unstable", - tester.autoscale(application1, cluster1, capacity).isEmpty()); + var fixture = AutoscalingTester.fixture().build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyLoad(0.9, 0.6, 0.7, 1, true, false, 120); + assertTrue("Not scaling up since nodes were measured while cluster was out of service", + fixture.autoscale().isEmpty()); } @Test 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 index 371cbe25e1b..429e0ce7030 100644 --- 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 @@ -63,6 +63,13 @@ public class Fixture { tester.deactivateRetired(application, cluster, capacity); } + 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 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); @@ -70,9 +77,9 @@ public class Fixture { tester().addQueryRateMeasurements(application, cluster.id(), measurements, samplingInterval, t -> t == 0 ? 20.0 : 10.0); // Query traffic only } - public void applyCpuLoad(double cpuLoad, int measurements) { + public void applyLoad(double cpuLoad, double memoryLoad, double diskLoad, int generation, boolean inService, boolean stable, int measurements) { Duration samplingInterval = Duration.ofSeconds(150L); // in addCpuMeasurements - tester().addCpuMeasurements((float)cpuLoad, 1.0f, measurements, application); + tester().addMeasurements((float)cpuLoad, (float)memoryLoad, (float)diskLoad, generation, inService, stable, 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 } -- cgit v1.2.3 From 525841eb27695bdf859ab8817b380eb9cf972479 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 19:49:40 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 29 +++++++++------------- 1 file changed, 12 insertions(+), 17 deletions(-) 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 b8fcb3a3660..1b7f297a3ed 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 @@ -291,23 +291,18 @@ public class AutoscalingTest { @Test public void test_autoscaling_group_size_1() { - NodeResources resources = new NodeResources(3, 100, 100, 1); - ClusterResources min = new ClusterResources( 2, 2, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources(20, 20, new NodeResources(100, 1000, 1000, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); - - // deploy - tester.deploy(application1, cluster1, 5, 5, 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 - tester.assertResources("Scaling up since resource usage is too high", - 7, 7, 2.5, 80.0, 50.5, - tester.autoscale(application1, cluster1, capacity)); + var min = new ClusterResources( 2, 2, new NodeResources(1, 1, 1, 1)); + var now = new ClusterResources(5, 5, new NodeResources(3, 100, 100, 1)); + var max = new ClusterResources(20, 20, new NodeResources(10, 1000, 1000, 1)); + var fixture = AutoscalingTester.fixture() + .initialResources(Optional.of(now)) + .capacity(Capacity.from(min, max)) + .build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyCpuLoad(0.9, 120); + fixture.tester().assertResources("Scaling the number of groups, but nothing requires us to stay with 1 node per group", + 10, 5, 7.7, 40.0, 40.0, + fixture.autoscale()); } @Test -- cgit v1.2.3 From a98be9842d56af0667b9eabcbcce5d5e9d390378 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 20:21:06 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 27 ++++++++-------------- .../provision/autoscale/AutoscalingTester.java | 6 +++-- .../vespa/hosted/provision/autoscale/Fixture.java | 9 ++++++++ 3 files changed, 23 insertions(+), 19 deletions(-) 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 1b7f297a3ed..e7d092ec37d 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 @@ -307,25 +307,18 @@ public class AutoscalingTest { @Test public void test_autoscaling_groupsize_by_cpu_read_dominated() { - NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 3, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources(21, 7, new NodeResources(100, 1000, 1000, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); - - // deploy - tester.deploy(application1, cluster1, 6, 2, resources); - tester.addCpuMeasurements(0.25f, 1f, 120, application1); - tester.clock().advance(Duration.ofMinutes(-10 * 5)); - tester.addLoadMeasurements(application1, cluster1.id(), 10, - t -> t == 0 ? 20.0 : 10.0, - t -> 1.0); - tester.assertResources("Scaling up since resource usage is too high, changing to 1 group is cheaper", - 8, 1, 2.6, 83.3, 52.6, - tester.autoscale(application1, cluster1, capacity)); + var fixture = AutoscalingTester.fixture() + .capacity(Capacity.from(min, max)) + .build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + Duration timePassed = fixture.addCpuMeasurements(0.25, 120); + fixture.tester().clock().advance(timePassed.negated()); + fixture.addLoadMeasurements(10, t -> t == 0 ? 20.0 : 10.0, t -> 1.0); + fixture.tester().assertResources("Scaling up since resource usage is too high, changing to 1 group is cheaper", + 9, 1, 1.8, 5.0, 50.0, + fixture.autoscale()); } /** Same as above but mostly write traffic, which favors smaller groups */ 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 e08444c6edb..748b8656358 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 @@ -163,10 +163,11 @@ class AutoscalingTester { * @param count the number of measurements * @param applicationId the application we're adding measurements for all nodes of */ - public void addCpuMeasurements(float value, float otherResourcesLoad, - int count, ApplicationId applicationId) { + public Duration addCpuMeasurements(float value, float otherResourcesLoad, + int count, ApplicationId applicationId) { NodeList nodes = nodeRepository().nodes().list(Node.State.active).owner(applicationId); float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size()); + Instant initialTime = clock().instant(); for (int i = 0; i < count; i++) { clock().advance(Duration.ofSeconds(150)); for (Node node : nodes) { @@ -182,6 +183,7 @@ class AutoscalingTester { 0.0)))); } } + 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 index 429e0ce7030..c99beed5170 100644 --- 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 @@ -10,6 +10,7 @@ import com.yahoo.vespa.hosted.provision.NodeList; import java.time.Duration; import java.util.Optional; +import java.util.function.IntFunction; /** * Fixture for autoscaling tests. @@ -63,6 +64,14 @@ public class Fixture { tester.deactivateRetired(application, cluster, capacity); } + public Duration addCpuMeasurements(double cpuLoad, int measurements) { + return tester().addCpuMeasurements((float)cpuLoad, 1.0f, measurements, application); + } + + public void addLoadMeasurements(int measurements, IntFunction queryRate, IntFunction writeRate) { + tester().addLoadMeasurements(application, cluster.id(), measurements, queryRate, writeRate); + } + public void applyCpuLoad(double cpuLoad, int measurements) { Duration samplingInterval = Duration.ofSeconds(150L); // in addCpuMeasurements tester().addCpuMeasurements((float)cpuLoad, 1.0f, measurements, application); -- cgit v1.2.3 From 8bb7399795d18de5402a0be653916b22b9177053 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 20:30:03 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 41 ++++++++++------------ 1 file changed, 19 insertions(+), 22 deletions(-) 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 e7d092ec37d..5d31cb55eb6 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 @@ -307,9 +307,11 @@ public class AutoscalingTest { @Test public void test_autoscaling_groupsize_by_cpu_read_dominated() { - ClusterResources min = new ClusterResources( 3, 1, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources(21, 7, new NodeResources(100, 1000, 1000, 1)); + var min = new ClusterResources( 3, 1, new NodeResources(1, 1, 1, 1)); + var now = new ClusterResources(6, 2, new NodeResources(3, 100, 100, 1)); + var max = new ClusterResources(21, 7, new NodeResources(100, 1000, 1000, 1)); var fixture = AutoscalingTester.fixture() + .initialResources(Optional.of(now)) .capacity(Capacity.from(min, max)) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); @@ -317,32 +319,27 @@ public class AutoscalingTest { fixture.tester().clock().advance(timePassed.negated()); fixture.addLoadMeasurements(10, t -> t == 0 ? 20.0 : 10.0, t -> 1.0); fixture.tester().assertResources("Scaling up since resource usage is too high, changing to 1 group is cheaper", - 9, 1, 1.8, 5.0, 50.0, + 10, 1, 2.3, 27.8, 27.8, fixture.autoscale()); } /** Same as above but mostly write traffic, which favors smaller groups */ @Test public void test_autoscaling_groupsize_by_cpu_write_dominated() { - NodeResources resources = new NodeResources(3, 100, 100, 1); - ClusterResources min = new ClusterResources( 3, 1, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources(21, 7, new NodeResources(100, 1000, 1000, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); - - // deploy - tester.deploy(application1, cluster1, 6, 2, resources); - tester.addCpuMeasurements(0.25f, 1f, 120, application1); - tester.clock().advance(Duration.ofMinutes(-10 * 5)); - tester.addLoadMeasurements(application1, cluster1.id(), 10, - t -> t == 0 ? 20.0 : 10.0, - t -> 100.0); - tester.assertResources("Scaling down since resource usage is too high, changing to 1 group is cheaper", - 4, 1, 2.1, 83.3, 52.6, - tester.autoscale(application1, cluster1, capacity)); + var min = new ClusterResources( 3, 1, new NodeResources(1, 1, 1, 1)); + var now = new ClusterResources(6, 2, new NodeResources(3, 100, 100, 1)); + var max = new ClusterResources(21, 7, new NodeResources(100, 1000, 1000, 1)); + var fixture = AutoscalingTester.fixture() + .initialResources(Optional.of(now)) + .capacity(Capacity.from(min, max)) + .build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + Duration timePassed = fixture.addCpuMeasurements(0.25, 120); + fixture.tester().clock().advance(timePassed.negated()); + fixture.addLoadMeasurements(10, t -> t == 0 ? 20.0 : 10.0, t -> 100.0); + fixture.tester().assertResources("Scaling down since resource usage is too high, changing to 1 group is cheaper", + 6, 1, 1.0, 50.0, 50.0, + fixture.autoscale()); } @Test -- cgit v1.2.3 From b6c2e9dea939550e80903bbd658b9bee1041b7b1 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 22:25:29 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 30 +++++++++------------- .../vespa/hosted/provision/autoscale/Fixture.java | 7 +++++ 2 files changed, 19 insertions(+), 18 deletions(-) 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 5d31cb55eb6..eafb4be0675 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 @@ -344,24 +344,18 @@ public class AutoscalingTest { @Test public void test_autoscaling_group_size() { - NodeResources hostResources = new NodeResources(100, 1000, 1000, 100); - ClusterResources min = new ClusterResources( 2, 2, new NodeResources(1, 1, 1, 1)); - ClusterResources max = new ClusterResources(30, 30, new NodeResources(100, 100, 1000, 1)); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(hostResources); - - 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)); - tester.clock().advance(Duration.ofDays(1)); - tester.addMemMeasurements(1.0f, 1f, 1000, 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("Increase group size to reduce memory load", - 8, 2, 12.4, 96.2, 62.5, - tester.autoscale(application1, cluster1, capacity)); + var min = new ClusterResources( 2, 2, new NodeResources(1, 1, 1, 1)); + var now = new ClusterResources(6, 2, new NodeResources(10, 100, 100, 1)); + var max = new ClusterResources(30, 30, new NodeResources(100, 100, 1000, 1)); + var fixture = AutoscalingTester.fixture() + .initialResources(Optional.of(now)) + .capacity(Capacity.from(min, max)) + .build(); + fixture.tester().clock().advance(Duration.ofDays(1)); + fixture.applyMemLoad(1.0, 1000); + fixture.tester().assertResources("Increase group size to reduce memory load", + 8, 2, 6.5, 96.2, 62.5, + fixture.autoscale()); } @Test 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 index c99beed5170..67a51caaed6 100644 --- 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 @@ -79,6 +79,13 @@ public class Fixture { tester().addQueryRateMeasurements(application, cluster.id(), measurements, samplingInterval, t -> t == 0 ? 20.0 : 10.0); // Query traffic only } + public void applyMemLoad(double memLoad, int measurements) { + Duration samplingInterval = Duration.ofSeconds(150L); // in addCpuMeasurements + tester().addMemMeasurements((float)memLoad, 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 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); -- cgit v1.2.3 From 23063b8d491d0c1b16b6aa35d3510f67c1a1940f Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 22:35:50 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 29 +++++++++------------- 1 file changed, 12 insertions(+), 17 deletions(-) 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 eafb4be0675..8900528b900 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 @@ -360,23 +360,18 @@ public class AutoscalingTest { @Test public void autoscaling_avoids_illegal_configurations() { - NodeResources hostResources = new NodeResources(6, 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(hostResources); - - 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)); - tester.clock().advance(Duration.ofDays(2)); - tester.addQueryRateMeasurements(application1, cluster1.id(), 100, t -> t == 0 ? 20.0 : 10.0); // Query traffic only - tester.addMemMeasurements(0.02f, 0.95f, 120, application1); - tester.assertResources("Scaling down", - 6, 1, 2.9, 4.0, 95.0, - tester.autoscale(application1, cluster1, capacity)); + var min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); + var now = new ClusterResources(6, 1, new NodeResources(3, 100, 100, 1)); + var max = new ClusterResources(20, 1, new NodeResources(100, 1000, 1000, 1)); + var fixture = AutoscalingTester.fixture() + .initialResources(Optional.of(now)) + .capacity(Capacity.from(min, max)) + .build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyMemLoad(0.02, 120); + fixture.tester().assertResources("Scaling down", + 6, 1, 3.1, 4.0, 100.0, + fixture.autoscale()); } @Test -- cgit v1.2.3 From 185ce3739aea35a6c07951972b40704018425018 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 17 Jul 2022 22:54:00 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 33 ++++++---------------- 1 file changed, 8 insertions(+), 25 deletions(-) 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 8900528b900..4a7f2426fac 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 @@ -376,31 +376,14 @@ public class AutoscalingTest { @Test public void scaling_down_only_after_delay() { - NodeResources hostResources = new NodeResources(6, 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(hostResources); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.content, "cluster1"); - - tester.deploy(application1, cluster1, 6, 1, hostResources.withVcpu(hostResources.vcpu() / 2)); - - // No autoscaling as it is too soon to scale down after initial deploy (counting as a scaling event) - tester.addMemMeasurements(0.02f, 0.95f, 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 - assertTrue(tester.autoscale(application1, cluster1, capacity).target().isEmpty()); - - // Trying the same later causes autoscaling - tester.clock().advance(Duration.ofDays(2)); - tester.addMemMeasurements(0.02f, 0.95f, 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", - 6, 1, 1.4, 4.0, 95.0, - tester.autoscale(application1, cluster1, capacity)); + var fixture = AutoscalingTester.fixture().build(); + fixture.applyMemLoad(0.02, 120); + assertTrue("Too soon after initial deployment", fixture.autoscale().target().isEmpty()); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyMemLoad(0.02, 120); + fixture.tester().assertResources("Scaling down since enough time has passed", + 6, 1, 1.2, 4.0, 80.0, + fixture.autoscale()); } @Test -- cgit v1.2.3 From 09ddb0276ba6d7433d932722a4ed49fd02a612f2 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Mon, 18 Jul 2022 12:50:28 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 49 +++++++--------------- .../provision/autoscale/AutoscalingTester.java | 18 ++++---- .../vespa/hosted/provision/autoscale/Fixture.java | 13 +++++- 3 files changed, 37 insertions(+), 43 deletions(-) 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 4a7f2426fac..59696f7d442 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 @@ -388,43 +388,24 @@ public class AutoscalingTest { @Test public void test_autoscaling_considers_real_resources() { - NodeResources hostResources = new NodeResources(60, 100, 1000, 10); - ClusterResources min = new ClusterResources(2, 1, new NodeResources( 2, 20, 200, 1)); - ClusterResources max = new ClusterResources(4, 1, new NodeResources(60, 100, 1000, 1)); - var capacity = Capacity.from(min, max); - { // No memory tax - AutoscalingTester tester = new AutoscalingTester(new Zone(Environment.prod, RegionName.from("us-east")), - hostResources, - new OnlySubtractingWhenForecastingCalculator(0)); - - 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); - 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 up", - 4, 1, 6.7, 20.5, 200, - tester.autoscale(application1, cluster1, capacity)); + var fixture = AutoscalingTester.fixture() + .resourceCalculator(new OnlySubtractingWhenForecastingCalculator(0)) + .build(); + fixture.applyLoad(1.0, 1.0, 0.7, 1000); + fixture.tester().assertResources("Scaling up", + 9, 1, 5.0, 9.6, 72.9, + fixture.autoscale()); } - { // 15 Gb memory tax - AutoscalingTester tester = new AutoscalingTester(new Zone(Environment.prod, RegionName.from("us-east")), - hostResources, - new OnlySubtractingWhenForecastingCalculator(15)); - - 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); - 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 up", - 4, 1, 6.7, 35.5, 200, - tester.autoscale(application1, cluster1, capacity)); + { + var fixture = AutoscalingTester.fixture() + .resourceCalculator(new OnlySubtractingWhenForecastingCalculator(3)) + .build(); + fixture.applyLoad(1.0, 1.0, 0.7, 1000); + fixture.tester().assertResources("With 3Gb memory tax, we scale up memory more", + 7, 1, 6.4, 15.8, 97.2, + fixture.autoscale()); } } 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 748b8656358..e3f85a16c3d 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 @@ -45,7 +45,7 @@ class AutoscalingTester { private final ProvisioningTester provisioningTester; private final Autoscaler autoscaler; - private final MockHostResourcesCalculator hostResourcesCalculator; + private final HostResourcesCalculator hostResourcesCalculator; private final CapacityPolicies capacityPolicies; /** Creates an autoscaling tester with a single host type ready */ @@ -76,7 +76,7 @@ class AutoscalingTester { } public AutoscalingTester(Zone zone, List flavors) { - this(zone, flavors, new MockHostResourcesCalculator(zone)); + this(zone, flavors, new MockHostResourcesCalculator(zone, 3)); } private AutoscalingTester(Zone zone, List flavors, HostResourcesCalculator resourcesCalculator) { @@ -86,7 +86,7 @@ class AutoscalingTester { .hostProvisioner(zone.getCloud().dynamicProvisioning() ? new MockHostProvisioner(flavors) : null) .build(); - hostResourcesCalculator = new MockHostResourcesCalculator(zone); + hostResourcesCalculator = resourcesCalculator; autoscaler = new Autoscaler(nodeRepository()); capacityPolicies = new CapacityPolicies(provisioningTester.nodeRepository()); } @@ -417,15 +417,17 @@ class AutoscalingTester { public static class MockHostResourcesCalculator implements HostResourcesCalculator { private final Zone zone; + private double memoryTax = 0; - public MockHostResourcesCalculator(Zone zone) { + public MockHostResourcesCalculator(Zone zone, double memoryTax) { this.zone = zone; + this.memoryTax = memoryTax; } @Override public NodeResources realResourcesOf(Nodelike node, NodeRepository nodeRepository) { if (zone.getCloud().dynamicProvisioning()) - return node.resources().withMemoryGb(node.resources().memoryGb() - 3); + return node.resources().withMemoryGb(node.resources().memoryGb() - memoryTax); else return node.resources(); } @@ -433,19 +435,19 @@ class AutoscalingTester { @Override public NodeResources advertisedResourcesOf(Flavor flavor) { if (zone.getCloud().dynamicProvisioning()) - return flavor.resources().withMemoryGb(flavor.resources().memoryGb() + 3); + return flavor.resources().withMemoryGb(flavor.resources().memoryGb() + memoryTax); else return flavor.resources(); } @Override public NodeResources requestToReal(NodeResources resources, boolean exclusive) { - return resources.withMemoryGb(resources.memoryGb() - 3); + return resources.withMemoryGb(resources.memoryGb() - memoryTax); } @Override public NodeResources realToRequest(NodeResources resources, boolean exclusive) { - return resources.withMemoryGb(resources.memoryGb() + 3); + return resources.withMemoryGb(resources.memoryGb() + memoryTax); } @Override 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 index 67a51caaed6..751e221f19e 100644 --- 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 @@ -5,8 +5,12 @@ 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.Environment; import com.yahoo.config.provision.NodeResources; +import com.yahoo.config.provision.RegionName; +import com.yahoo.config.provision.Zone; import com.yahoo.vespa.hosted.provision.NodeList; +import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator; import java.time.Duration; import java.util.Optional; @@ -28,7 +32,7 @@ public class Fixture { application = builder.application; cluster = builder.cluster; capacity = builder.capacity; - tester = new AutoscalingTester(builder.hostResources); + tester = new AutoscalingTester(builder.zone, builder.hostResources, builder.resourceCalculator); var deployCapacity = initialResources.isPresent() ? Capacity.from(initialResources.get()) : capacity; tester.deploy(builder.application, builder.cluster, deployCapacity); } @@ -111,6 +115,8 @@ public class Fixture { ApplicationId application = AutoscalingTester.applicationId("application1"); ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("cluster1")).vespaVersion("7").build(); + Zone zone = new Zone(Environment.prod, RegionName.from("us-east")); + HostResourcesCalculator resourceCalculator = new AutoscalingTester.MockHostResourcesCalculator(zone, 0); public Fixture.Builder clusterType(ClusterSpec.Type type) { cluster = ClusterSpec.request(type, cluster.id()).vespaVersion("7").build(); @@ -132,6 +138,11 @@ public class Fixture { return this; } + public Fixture.Builder resourceCalculator(HostResourcesCalculator resourceCalculator) { + this.resourceCalculator = resourceCalculator; + return this; + } + public Fixture build() { return new Fixture(this, initialResources); } -- cgit v1.2.3 From bef65c951ee5d1ad986e6e6ec8ab2e16726fc34b Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Mon, 18 Jul 2022 13:02:28 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 42 ++++++++++------------ .../provision/autoscale/AutoscalingTester.java | 8 ----- .../vespa/hosted/provision/autoscale/Fixture.java | 4 +++ 3 files changed, 22 insertions(+), 32 deletions(-) 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 59696f7d442..b135d913fde 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 @@ -452,34 +452,28 @@ public class AutoscalingTest { @Test public void test_autoscaling_considers_read_share() { - NodeResources resources = new NodeResources(3, 100, 100, 1); - ClusterResources min = new ClusterResources( 1, 1, resources); - ClusterResources max = new ClusterResources(10, 1, resources); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2)); - - 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 - tester.clock().advance(Duration.ofMinutes(-100 * 5)); - tester.addCpuMeasurements(0.25f, 1f, 100, application1); + var min = new ClusterResources( 1, 1, new NodeResources(3, 100, 100, 1)); + var max = new ClusterResources(10, 1, new NodeResources(3, 100, 100, 1)); + var fixture = AutoscalingTester.fixture() + .capacity(Capacity.from(min, max)) + .build(); + fixture.tester.clock().advance(Duration.ofDays(1)); + fixture.applyCpuLoad(0.25, 120); // (no read share stored) - tester.assertResources("Advice to scale up since we set aside for bcp by default", - 7, 1, 3, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().assertResources("Advice to scale up since we set aside for bcp by default", + 7, 1, 3, 100, 100, + fixture.autoscale()); - tester.storeReadShare(0.25, 0.5, application1); - tester.assertResources("Half of global share is the same as the default assumption used above", - 7, 1, 3, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.storeReadShare(0.25, 0.5); + fixture.tester().assertResources("Half of global share is the same as the default assumption used above", + 7, 1, 3, 100, 100, + fixture.autoscale()); - tester.storeReadShare(0.5, 0.5, application1); - tester.assertResources("Advice to scale down since we don't need room for bcp", - 4, 1, 3, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.storeReadShare(0.5, 0.5); + fixture.tester().assertResources("Advice to scale down since we don't need room for bcp", + 6, 1, 3, 100, 100, + fixture.autoscale()); } @Test 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 e3f85a16c3d..2a052c308b6 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 @@ -57,14 +57,6 @@ class AutoscalingTester { this(new Zone(environment, RegionName.from("us-east")), hostResources, null); } - public AutoscalingTester(Zone zone, NodeResources hostResources) { - this(zone, hostResources, null); - } - - public AutoscalingTester(Zone zone, NodeResources hostResources, int hostCount) { - this(zone, hostResources, null, hostCount); - } - public AutoscalingTester(Zone zone, NodeResources hostResources, HostResourcesCalculator resourcesCalculator) { this(zone, hostResources, resourcesCalculator, 20); } 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 index 751e221f19e..fe291eb6c6b 100644 --- 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 @@ -104,6 +104,10 @@ public class Fixture { tester().addQueryRateMeasurements(application, cluster.id(), measurements, samplingInterval, t -> t == 0 ? 20.0 : 10.0); // Query traffic only } + public void storeReadShare(double currentReadShare, double maxReadShare) { + tester.storeReadShare(currentReadShare, maxReadShare, application); + } + public static class Builder { NodeResources hostResources = new NodeResources(100, 100, 100, 1); -- cgit v1.2.3 From 4f0dc2004a5ad95d471be054af7dfacb56dd8fb3 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Mon, 18 Jul 2022 13:27:17 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 68 +++++++++++----------- .../provision/autoscale/AutoscalingTester.java | 8 +-- .../vespa/hosted/provision/autoscale/Fixture.java | 18 +++--- 3 files changed, 47 insertions(+), 47 deletions(-) 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 b135d913fde..68dafa6f034 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 @@ -478,48 +478,46 @@ public class AutoscalingTest { @Test public void test_autoscaling_considers_growth_rate() { - NodeResources minResources = new NodeResources( 1, 100, 100, 1); - NodeResources midResources = new NodeResources( 5, 100, 100, 1); - NodeResources maxResources = new NodeResources(10, 100, 100, 1); - ClusterResources min = new ClusterResources(5, 1, minResources); - ClusterResources max = new ClusterResources(5, 1, maxResources); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(maxResources.withVcpu(maxResources.vcpu() * 2)); + var min = new ClusterResources(5, 1, new NodeResources( 1, 100, 100, 1)); + var now = new ClusterResources(5, 1, new NodeResources( 5, 100, 100, 1)); + var max = new ClusterResources(5, 1, new NodeResources(10, 100, 100, 1)); + var fixture = AutoscalingTester.fixture() + .initialResources(Optional.of(now)) + .capacity(Capacity.from(min, max)) + .build(); - 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); - tester.clock().advance(timeAdded.negated()); - tester.addCpuMeasurements(0.25f, 1f, 200, application1); + fixture.tester().clock().advance(Duration.ofDays(2)); + Duration timeAdded = fixture.addLoadMeasurements(100, t -> t == 0 ? 20.0 : 10.0, t -> 0.0); + fixture.tester.clock().advance(timeAdded.negated()); + fixture.addCpuMeasurements(0.25, 200); // (no query rate data) - tester.assertResources("Scale up since we assume we need 2x cpu for growth when no data scaling time data", - 5, 1, 6.3, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().assertResources("Scale up since we assume we need 2x cpu for growth when no data scaling time data", + 5, 1, 6.4, 100, 100, + fixture.autoscale()); - tester.setScalingDuration(application1, cluster1.id(), Duration.ofMinutes(5)); - timeAdded = tester.addQueryRateMeasurements(application1, cluster1.id(), - 100, - t -> 10.0 + (t < 50 ? t : 100 - t)); - tester.clock().advance(timeAdded.negated()); - tester.addCpuMeasurements(0.25f, 1f, 200, application1); - tester.assertResources("Scale down since observed growth is slower than scaling time", - 5, 1, 3.4, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.setScalingDuration(Duration.ofMinutes(5)); + + fixture.tester().clock().advance(Duration.ofDays(2)); + timeAdded = fixture.addLoadMeasurements(100, t -> 10.0 + (t < 50 ? t : 100 - t), t -> 0.0); + fixture.tester.clock().advance(timeAdded.negated()); + fixture.addCpuMeasurements(0.25, 200); + fixture.tester().assertResources("Scale down since observed growth is slower than scaling time", + 5, 1, 5.6, 100, 100, + fixture.autoscale()); - tester.clearQueryRateMeasurements(application1, cluster1.id()); + fixture.setScalingDuration(Duration.ofMinutes(60)); - tester.setScalingDuration(application1, cluster1.id(), Duration.ofMinutes(60)); - timeAdded = tester.addQueryRateMeasurements(application1, cluster1.id(), - 100, - t -> 10.0 + (t < 50 ? t * t * t : 125000 - (t - 49) * (t - 49) * (t - 49))); - tester.clock().advance(timeAdded.negated()); - tester.addCpuMeasurements(0.25f, 1f, 200, application1); - tester.assertResources("Scale up since observed growth is faster than scaling time", - 5, 1, 10.0, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().clock().advance(Duration.ofDays(2)); + timeAdded = fixture.addLoadMeasurements(100, + t -> 10.0 + (t < 50 ? t * t * t : 125000 - (t - 49) * (t - 49) * (t - 49)), + t -> 0.0); + fixture.tester.clock().advance(timeAdded.negated()); + fixture.addCpuMeasurements(0.25, 200); + fixture.tester().assertResources("Scale up since observed growth is faster than scaling time", + 5, 1, 6.6, 100, 100, + fixture.autoscale()); } @Test 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 2a052c308b6..371d5dbee59 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 @@ -299,11 +299,12 @@ class AutoscalingTester { } /** Creates the given number of measurements, spaced 5 minutes between, using the given function */ - public void addLoadMeasurements(ApplicationId application, + public Duration addLoadMeasurements(ApplicationId application, ClusterSpec.Id cluster, int measurements, IntFunction queryRate, IntFunction writeRate) { + Instant initialTime = clock().instant(); for (int i = 0; i < measurements; i++) { nodeMetricsDb().addClusterMetrics(application, Map.of(cluster, new ClusterMetricSnapshot(clock().instant(), @@ -311,6 +312,7 @@ class AutoscalingTester { writeRate.apply(i)))); clock().advance(Duration.ofMinutes(5)); } + return Duration.between(initialTime, clock().instant()); } /** Creates the given number of measurements, spaced 5 minutes between, using the given function */ @@ -337,10 +339,6 @@ class AutoscalingTester { return Duration.between(initialTime, clock().instant()); } - public void clearQueryRateMeasurements(ApplicationId application, ClusterSpec.Id cluster) { - ((MemoryMetricsDb)nodeMetricsDb()).clearClusterMetrics(application, cluster); - } - public Autoscaler.Advice autoscale(ApplicationId applicationId, ClusterSpec cluster, Capacity capacity) { capacity = capacityPolicies.applyOn(capacity, applicationId, capacityPolicies.decideExclusivity(capacity, cluster.isExclusive())); Application application = nodeRepository().applications().get(applicationId).orElse(Application.empty(applicationId)) 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 index fe291eb6c6b..602b6189898 100644 --- 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 @@ -46,7 +46,7 @@ public class Fixture { /** Autoscale within the given capacity. */ public Autoscaler.Advice autoscale(Capacity capacity) { - return tester.autoscale(application, cluster, capacity); + return tester().autoscale(application, cluster, capacity); } /** Redeploy with the deployed capacity of this. */ @@ -56,24 +56,28 @@ public class Fixture { /** Redeploy with the given capacity. */ public void deploy(Capacity capacity) { - tester.deploy(application, cluster, capacity); + tester().deploy(application, cluster, capacity); } /** Returns the nodes allocated to the fixture application cluster */ public NodeList nodes() { - return tester.nodeRepository().nodes().list().owner(application).cluster(cluster.id()); + return tester().nodeRepository().nodes().list().owner(application).cluster(cluster.id()); } public void deactivateRetired(Capacity capacity) { - tester.deactivateRetired(application, cluster, capacity); + tester().deactivateRetired(application, cluster, capacity); + } + + public void setScalingDuration(Duration duration) { + tester().setScalingDuration(application, cluster.id(), duration); } public Duration addCpuMeasurements(double cpuLoad, int measurements) { return tester().addCpuMeasurements((float)cpuLoad, 1.0f, measurements, application); } - public void addLoadMeasurements(int measurements, IntFunction queryRate, IntFunction writeRate) { - tester().addLoadMeasurements(application, cluster.id(), measurements, queryRate, writeRate); + public Duration addLoadMeasurements(int measurements, IntFunction queryRate, IntFunction writeRate) { + return tester().addLoadMeasurements(application, cluster.id(), measurements, queryRate, writeRate); } public void applyCpuLoad(double cpuLoad, int measurements) { @@ -105,7 +109,7 @@ public class Fixture { } public void storeReadShare(double currentReadShare, double maxReadShare) { - tester.storeReadShare(currentReadShare, maxReadShare, application); + tester().storeReadShare(currentReadShare, maxReadShare, application); } public static class Builder { -- cgit v1.2.3 From 9b944fb02e8c0819059080026592ccdf137d35b2 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Mon, 18 Jul 2022 13:58:54 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 98 ++++++++++------------ 1 file changed, 42 insertions(+), 56 deletions(-) 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 68dafa6f034..9e79949efb6 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 @@ -478,37 +478,27 @@ public class AutoscalingTest { @Test public void test_autoscaling_considers_growth_rate() { - var min = new ClusterResources(5, 1, new NodeResources( 1, 100, 100, 1)); - var now = new ClusterResources(5, 1, new NodeResources( 5, 100, 100, 1)); - var max = new ClusterResources(5, 1, new NodeResources(10, 100, 100, 1)); - var fixture = AutoscalingTester.fixture() - .initialResources(Optional.of(now)) - .capacity(Capacity.from(min, max)) - .build(); - + var fixture = AutoscalingTester.fixture().build(); fixture.tester().clock().advance(Duration.ofDays(2)); Duration timeAdded = fixture.addLoadMeasurements(100, t -> t == 0 ? 20.0 : 10.0, t -> 0.0); fixture.tester.clock().advance(timeAdded.negated()); fixture.addCpuMeasurements(0.25, 200); - // (no query rate data) fixture.tester().assertResources("Scale up since we assume we need 2x cpu for growth when no data scaling time data", - 5, 1, 6.4, 100, 100, + 9, 1, 2.1, 5, 50, fixture.autoscale()); fixture.setScalingDuration(Duration.ofMinutes(5)); - fixture.tester().clock().advance(Duration.ofDays(2)); timeAdded = fixture.addLoadMeasurements(100, t -> 10.0 + (t < 50 ? t : 100 - t), t -> 0.0); fixture.tester.clock().advance(timeAdded.negated()); fixture.addCpuMeasurements(0.25, 200); fixture.tester().assertResources("Scale down since observed growth is slower than scaling time", - 5, 1, 5.6, 100, 100, + 9, 1, 1.8, 5, 50, fixture.autoscale()); fixture.setScalingDuration(Duration.ofMinutes(60)); - fixture.tester().clock().advance(Duration.ofDays(2)); timeAdded = fixture.addLoadMeasurements(100, t -> 10.0 + (t < 50 ? t * t * t : 125000 - (t - 49) * (t - 49) * (t - 49)), @@ -516,63 +506,59 @@ public class AutoscalingTest { fixture.tester.clock().advance(timeAdded.negated()); fixture.addCpuMeasurements(0.25, 200); fixture.tester().assertResources("Scale up since observed growth is faster than scaling time", - 5, 1, 6.6, 100, 100, + 9, 1, 2.1, 5, 50, fixture.autoscale()); } @Test public void test_autoscaling_considers_query_vs_write_rate() { - NodeResources minResources = new NodeResources( 1, 100, 100, 1); - NodeResources midResources = new NodeResources( 5, 100, 100, 1); - NodeResources maxResources = new NodeResources(10, 100, 100, 1); - ClusterResources min = new ClusterResources(5, 1, minResources); - ClusterResources max = new ClusterResources(5, 1, maxResources); - var capacity = Capacity.from(min, max); - AutoscalingTester tester = new AutoscalingTester(maxResources.withVcpu(maxResources.vcpu() * 2)); - - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + var fixture = AutoscalingTester.fixture().build(); - tester.deploy(application1, cluster1, 5, 1, midResources); - tester.addCpuMeasurements(0.4f, 1f, 120, application1); + fixture.addCpuMeasurements(0.4, 220); // Why twice the query rate at time = 0? // This makes headroom for queries doubling, which we want to observe the effect of here - tester.addCpuMeasurements(0.4f, 1f, 100, application1); - tester.clock().advance(Duration.ofMinutes(-100 * 5)); - tester.addLoadMeasurements(application1, cluster1.id(), 100, t -> t == 0 ? 20.0 : 10.0, t -> 10.0); - tester.assertResources("Query and write load is equal -> scale up somewhat", - 5, 1, 7.3, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().clock().advance(Duration.ofDays(2)); + var timeAdded = fixture.addLoadMeasurements(100, t -> t == 0 ? 20.0 : 10.0, t -> 10.0); + fixture.tester.clock().advance(timeAdded.negated()); + fixture.addCpuMeasurements(0.4, 200); + fixture.tester.assertResources("Query and write load is equal -> scale up somewhat", + 9, 1, 2.4, 5, 50, + fixture.autoscale()); - tester.addCpuMeasurements(0.4f, 1f, 100, application1); - tester.clock().advance(Duration.ofMinutes(-100 * 5)); - tester.addLoadMeasurements(application1, cluster1.id(), 100, t -> t == 0 ? 80.0 : 40.0, t -> 10.0); - tester.assertResources("Query load is 4x write load -> scale up more", - 5, 1, 9.5, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().clock().advance(Duration.ofDays(2)); + timeAdded = fixture.addLoadMeasurements(100, t -> t == 0 ? 80.0 : 40.0, t -> 10.0); + fixture.tester.clock().advance(timeAdded.negated()); + fixture.addCpuMeasurements(0.4, 200); + // TODO: Ackhually, we scale down here - why? + fixture.tester().assertResources("Query load is 4x write load -> scale up more", + 9, 1, 2.1, 5, 50, + fixture.autoscale()); - tester.addCpuMeasurements(0.3f, 1f, 100, application1); - tester.clock().advance(Duration.ofMinutes(-100 * 5)); - tester.addLoadMeasurements(application1, cluster1.id(), 100, t -> t == 0 ? 20.0 : 10.0, t -> 100.0); - tester.assertResources("Write load is 10x query load -> scale down", - 5, 1, 2.9, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().clock().advance(Duration.ofDays(2)); + timeAdded = fixture.addLoadMeasurements(100, t -> t == 0 ? 20.0 : 10.0, t -> 100.0); + fixture.tester.clock().advance(timeAdded.negated()); + fixture.addCpuMeasurements(0.4, 200); + fixture.tester().assertResources("Write load is 10x query load -> scale down", + 9, 1, 1.1, 5, 50, + fixture.autoscale()); - tester.addCpuMeasurements(0.4f, 1f, 100, application1); - tester.clock().advance(Duration.ofMinutes(-100 * 5)); - tester.addLoadMeasurements(application1, cluster1.id(), 100, t -> t == 0 ? 20.0 : 10.0, t-> 0.0); - tester.assertResources("Query only -> largest possible", - 5, 1, 10.0, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().clock().advance(Duration.ofDays(2)); + timeAdded = fixture.addLoadMeasurements(100, t -> t == 0 ? 20.0 : 10.0, t-> 0.0); + fixture.tester.clock().advance(timeAdded.negated()); + fixture.addCpuMeasurements(0.4, 200); + fixture.tester().assertResources("Query only -> largest possible", + 8, 1, 4.9, 5.7, 57.1, + fixture.autoscale()); - tester.addCpuMeasurements(0.4f, 1f, 100, application1); - tester.clock().advance(Duration.ofMinutes(-100 * 5)); - tester.addLoadMeasurements(application1, cluster1.id(), 100, t -> 0.0, t -> 10.0); - tester.assertResources("Write only -> smallest possible", - 5, 1, 2.1, 100, 100, - tester.autoscale(application1, cluster1, capacity)); + fixture.tester().clock().advance(Duration.ofDays(2)); + timeAdded = fixture.addLoadMeasurements(100, t -> 0.0, t -> 10.0); + fixture.tester.clock().advance(timeAdded.negated()); + fixture.addCpuMeasurements(0.4, 200); + fixture.tester().assertResources("Write only -> smallest possible", + 6, 1, 1.0, 8, 80, + fixture.autoscale()); } @Test -- cgit v1.2.3 From dde3daae88460f558060edb9912664de5a062b40 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Mon, 18 Jul 2022 14:26:00 +0200 Subject: Use fixture and handle just 1 node --- .../provision/autoscale/AllocationOptimizer.java | 6 +++--- .../hosted/provision/autoscale/AutoscalingTest.java | 18 ++++-------------- .../vespa/hosted/provision/autoscale/Fixture.java | 5 +++++ 3 files changed, 12 insertions(+), 17 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 41fa9499353..5bebd346bdb 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 @@ -57,8 +57,8 @@ public class AllocationOptimizer { // Adjust for redundancy: Node in group if groups = 1, an extra group if multiple groups // TODO: Make the best choice based on size and redundancy setting instead - int nodesAdjustedForRedundancy = target.adjustForRedundancy() ? (groups == 1 ? nodes - 1 : nodes - groupSize) : nodes; - int groupsAdjustedForRedundancy = target.adjustForRedundancy() ? (groups == 1 ? 1 : groups - 1) : groups; + int nodesAdjustedForRedundancy = target.adjustForRedundancy() && nodes > 1 ? (groups == 1 ? nodes - 1 : nodes - groupSize) : nodes; + int groupsAdjustedForRedundancy = target.adjustForRedundancy() && nodes > 1 ? (groups == 1 ? 1 : groups - 1) : groups; ClusterResources next = new ClusterResources(nodes, groups, @@ -95,6 +95,7 @@ public class AllocationOptimizer { // The fixed cost portion of cpu does not scale with changes to the node count double queryCpuPerGroup = fixedCpuCostFraction * target.resources().vcpu() + (1 - fixedCpuCostFraction) * target.resources().vcpu() * current.groupSize() / groupSize; + double queryCpu = queryCpuPerGroup * current.groups() / groups; double writeCpu = target.resources().vcpu() * current.groupSize() / groupSize; cpu = clusterModel.queryCpuFraction() * queryCpu + (1 - clusterModel.queryCpuFraction()) * writeCpu; @@ -106,7 +107,6 @@ public class AllocationOptimizer { memory = target.resources().memoryGb(); disk = target.resources().diskGb(); } - // Combine the scaled resource values computed here // with the currently configured non-scaled values, given in the limits, if any NodeResources nonScaled = limits.isEmpty() || limits.min().nodeResources().isUnspecified() 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 9e79949efb6..b512852a5e7 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 @@ -563,21 +563,11 @@ public class AutoscalingTest { @Test public void test_autoscaling_in_dev() { - NodeResources resources = new NodeResources(1, 4, 50, 1); - ClusterResources min = new ClusterResources( 1, 1, resources); - ClusterResources max = new ClusterResources(3, 1, resources); - Capacity capacity = Capacity.from(min, max, false, true); - - AutoscalingTester tester = new AutoscalingTester(Environment.dev, resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); - - tester.deploy(application1, cluster1, capacity); - tester.addQueryRateMeasurements(application1, cluster1.id(), - 500, t -> 100.0); - tester.addCpuMeasurements(1.0f, 1f, 10, application1); + var fixture = AutoscalingTester.fixture().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyLoad(1.0, 1.0, 1.0, 200); assertTrue("Not attempting to scale up because policies dictate we'll only get one node", - tester.autoscale(application1, cluster1, capacity).target().isEmpty()); + fixture.autoscale().target().isEmpty()); } /** Same setup as test_autoscaling_in_dev(), just with required = true */ 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 index 602b6189898..efdeab4e6ee 100644 --- 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 @@ -126,6 +126,11 @@ public class Fixture { Zone zone = new Zone(Environment.prod, RegionName.from("us-east")); HostResourcesCalculator resourceCalculator = new AutoscalingTester.MockHostResourcesCalculator(zone, 0); + public Fixture.Builder zone(Zone zone) { + this.zone = zone; + return this; + } + public Fixture.Builder clusterType(ClusterSpec.Type type) { cluster = ClusterSpec.request(type, cluster.id()).vespaVersion("7").build(); return this; -- cgit v1.2.3 From 48f019e7a249bfb1668c49bc9d0cc90b4fb377df Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Mon, 18 Jul 2022 14:43:15 +0200 Subject: Use fixture --- .../provision/autoscale/AutoscalingTest.java | 65 +++++++++++----------- .../vespa/hosted/provision/autoscale/Fixture.java | 1 - 2 files changed, 33 insertions(+), 33 deletions(-) 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 b512852a5e7..a2eb5fba9f9 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 @@ -563,7 +563,9 @@ public class AutoscalingTest { @Test public void test_autoscaling_in_dev() { - var fixture = AutoscalingTester.fixture().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); + var fixture = AutoscalingTester.fixture() + .zone(new Zone(Environment.dev, RegionName.from("us-east"))) + .build(); fixture.tester().clock().advance(Duration.ofDays(2)); fixture.applyLoad(1.0, 1.0, 1.0, 200); assertTrue("Not attempting to scale up because policies dictate we'll only get one node", @@ -573,43 +575,42 @@ public class AutoscalingTest { /** Same setup as test_autoscaling_in_dev(), just with required = true */ @Test public void test_autoscaling_in_dev_with_required_resources() { - NodeResources resources = new NodeResources(1, 4, 50, 1); - ClusterResources min = new ClusterResources( 1, 1, resources); - ClusterResources max = new ClusterResources(3, 1, resources); - Capacity capacity = Capacity.from(min, max, true, true); - - AutoscalingTester tester = new AutoscalingTester(Environment.dev, resources.withVcpu(resources.vcpu() * 2)); - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); + var requiredCapacity = + Capacity.from(new ClusterResources(2, 1, + new NodeResources(1, 1, 1, 1, NodeResources.DiskSpeed.any)), + new ClusterResources(20, 1, + new NodeResources(100, 1000, 1000, 1, NodeResources.DiskSpeed.any)), + true, + true); - tester.deploy(application1, cluster1, capacity); - tester.addQueryRateMeasurements(application1, cluster1.id(), - 500, t -> 100.0); - tester.addCpuMeasurements(1.0f, 1f, 10, application1); - tester.assertResources("We scale up even in dev because resources are required", - 3, 1, 1.0, 4, 50, - tester.autoscale(application1, cluster1, capacity)); + var fixture = AutoscalingTester.fixture() + .capacity(requiredCapacity) + .zone(new Zone(Environment.dev, RegionName.from("us-east"))) + .build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyLoad(1.0, 1.0, 1.0, 200); + fixture.tester().assertResources("We scale even in dev because resources are required", + 3, 1, 1.0, 7.7, 83.3, + fixture.autoscale()); } @Test public void test_autoscaling_in_dev_with_required_unspecified_resources() { - NodeResources resources = NodeResources.unspecified(); - ClusterResources min = new ClusterResources( 1, 1, resources); - ClusterResources max = new ClusterResources(3, 1, resources); - Capacity capacity = Capacity.from(min, max, true, true); + var requiredCapacity = + Capacity.from(new ClusterResources(1, 1, NodeResources.unspecified()), + new ClusterResources(3, 1, NodeResources.unspecified()), + true, + true); - AutoscalingTester tester = new AutoscalingTester(Environment.dev, - new NodeResources(10, 16, 100, 2)); - ApplicationId application1 = AutoscalingTester.applicationId("application1"); - ClusterSpec cluster1 = AutoscalingTester.clusterSpec(ClusterSpec.Type.container, "cluster1"); - - tester.deploy(application1, cluster1, capacity); - tester.addQueryRateMeasurements(application1, cluster1.id(), - 500, t -> 100.0); - tester.addCpuMeasurements(1.0f, 1f, 10, application1); - tester.assertResources("We scale up even in dev because resources are required", - 3, 1, 1.5, 8, 50, - tester.autoscale(application1, cluster1, capacity)); + var fixture = AutoscalingTester.fixture() + .capacity(requiredCapacity) + .zone(new Zone(Environment.dev, RegionName.from("us-east"))) + .build(); + fixture.tester().clock().advance(Duration.ofDays(2)); + fixture.applyLoad(1.0, 1.0, 1.0, 200); + fixture.tester().assertResources("We scale even in dev because resources are required", + 3, 1, 1.5, 8, 50, + fixture.autoscale()); } /** 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 index efdeab4e6ee..896897f45c1 100644 --- 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 @@ -120,7 +120,6 @@ public class Fixture { new NodeResources(1, 1, 1, 1, NodeResources.DiskSpeed.any)), 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(); Zone zone = new Zone(Environment.prod, RegionName.from("us-east")); -- cgit v1.2.3 From 253cafdebf0f56dfcd5670d78bd4f7ff934b117e Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Mon, 18 Jul 2022 14:44:13 +0200 Subject: Cleanup --- .../com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java | 4 ---- 1 file changed, 4 deletions(-) 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 371d5dbee59..2a4dbe32ab5 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 @@ -250,10 +250,6 @@ class AutoscalingTester { 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); - } - public void addMeasurements(float cpu, float memory, float disk, int generation, boolean inService, boolean stable, int count, ApplicationId applicationId) { NodeList nodes = nodeRepository().nodes().list(Node.State.active).owner(applicationId); -- cgit v1.2.3