diff options
author | Jon Bratseth <bratseth@gmail.com> | 2020-05-20 12:39:25 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2020-05-20 12:39:25 +0200 |
commit | 1169f81d3de87312ca33fc7167a7a62ab4aa2cc1 (patch) | |
tree | 6a6a9ab7c6921de24bed0f6cc6b482c169a410c9 /node-repository | |
parent | 47371c7bfc2e17ff167558069b9067231f827550 (diff) |
Remove groups immediately
Since we don't change group assignment for existing nodes any more
we don't need to retire nodes from removed groups but can remove
them immediately.
Diffstat (limited to 'node-repository')
9 files changed, 111 insertions, 82 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java index 6097688df72..1b2f73a2f5f 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java @@ -161,4 +161,9 @@ public class NodeList extends AbstractFilteringList<Node, NodeList> { return new NodeList(nodes, false); } + @Override + public String toString() { + return asList().toString(); + } + } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java index 4452fc21c52..ad3dbc7eaa5 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java @@ -73,7 +73,7 @@ class Preparer { replace(acceptedNodes, accepted); } moveToActiveGroup(surplusNodes, wantedGroups, cluster.group()); - replace(acceptedNodes, retire(surplusNodes)); + acceptedNodes.removeAll(surplusNodes); return acceptedNodes; } @@ -140,13 +140,4 @@ class Preparer { return highestIndex; } - /** Returns retired copies of the given nodes, unless they are removable */ - private List<Node> retire(List<Node> nodes) { - List<Node> retired = new ArrayList<>(nodes.size()); - for (Node node : nodes) { - if ( ! node.allocation().get().isRemovable()) - retired.add(node.retire(Agent.application, nodeRepository.clock().instant())); - } - return retired; - } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/PrioritizableNode.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/PrioritizableNode.java index a60dee6bb0c..3fc60c1192d 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/PrioritizableNode.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/PrioritizableNode.java @@ -74,14 +74,14 @@ class PrioritizableNode implements Comparable<PrioritizableNode> { if (!this.isSurplusNode && other.isSurplusNode) return -1; if (!other.isSurplusNode && this.isSurplusNode) return 1; - // Choose inactive nodes - if (this.node.state() == Node.State.inactive && other.node.state() != Node.State.inactive) return -1; - if (other.node.state() == Node.State.inactive && this.node.state() != Node.State.inactive) return 1; - // Choose reserved nodes from a previous allocation attempt (the exist in node repo) if (this.isInNodeRepoAndReserved() && ! other.isInNodeRepoAndReserved()) return -1; if (other.isInNodeRepoAndReserved() && ! this.isInNodeRepoAndReserved()) return 1; + // Choose inactive nodes + if (this.node.state() == Node.State.inactive && other.node.state() != Node.State.inactive) return -1; + if (other.node.state() == Node.State.inactive && this.node.state() != Node.State.inactive) return 1; + // Choose ready nodes if (this.node.state() == Node.State.ready && other.node.state() != Node.State.ready) return -1; if (other.node.state() == Node.State.ready && this.node.state() != Node.State.ready) return 1; 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 781ef1f6114..08e4237fe00 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 @@ -248,7 +248,6 @@ public class AutoscalingTest { // deploy tester.deploy(application1, cluster1, 6, 2, resources); tester.addMeasurements(Resource.cpu, 0.25f, 1f, 120, application1); - System.out.println("Autoscaling ... "); tester.assertResources("Scaling up since resource usage is too high, changing to 1 group is cheaper", 8, 1, 2.7, 83.3, 83.3, tester.autoscale(application1, cluster1.id(), min, max)); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java index e57bae09280..addbf717811 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java @@ -119,37 +119,6 @@ public class RetiredExpirerTest { } @Test - public void ensure_retired_groups_time_out() { - createReadyNodes(8, nodeResources, nodeRepository); - createHostNodes(4, nodeRepository, nodeFlavors); - - ApplicationId applicationId = ApplicationId.from(TenantName.from("foo"), ApplicationName.from("bar"), InstanceName.from("fuz")); - - ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); - activate(applicationId, cluster, 8, 8, provisioner); - activate(applicationId, cluster, 2, 2, provisioner); - assertEquals(8, nodeRepository.getNodes(applicationId, Node.State.active).size()); - assertEquals(0, nodeRepository.getNodes(applicationId, Node.State.inactive).size()); - - // Cause inactivation of retired nodes - clock.advance(Duration.ofHours(30)); // Retire period spent - MockDeployer deployer = - new MockDeployer(provisioner, - clock, - Collections.singletonMap(applicationId, new MockDeployer.ApplicationContext(applicationId, - cluster, - Capacity.from(new ClusterResources(2, 1, nodeResources))))); - createRetiredExpirer(deployer).run(); - assertEquals(2, nodeRepository.getNodes(applicationId, Node.State.active).size()); - assertEquals(6, nodeRepository.getNodes(applicationId, Node.State.inactive).size()); - assertEquals(1, deployer.redeployments); - - // inactivated nodes are not retired - for (Node node : nodeRepository.getNodes(applicationId, Node.State.inactive)) - assertFalse(node.allocation().get().membership().retired()); - } - - @Test public void ensure_early_inactivation() throws OrchestrationException { createReadyNodes(7, nodeResources, nodeRepository); createHostNodes(4, nodeRepository, nodeFlavors); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java index 3b03e4e9d91..6e609d13d3b 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java @@ -6,6 +6,7 @@ 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.Flavor; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.RegionName; @@ -21,6 +22,7 @@ import java.time.Duration; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -121,6 +123,99 @@ public class MultigroupProvisioningTest { deploy(application1, Capacity.from(new ClusterResources(2, 2, large), true, true), tester); } + /** + * When increasing the number of groups without changing node count, we need to provison new nodes for + * the new groups since although we can remove nodes from existing groups without losing data we + * cannot do so without losing coverage. + */ + @Test + public void test_split_to_groups() { + Flavor hostFlavor = new Flavor(new NodeResources(20, 40, 100, 4)); + ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))) + .flavors(List.of(hostFlavor)) + .build(); + tester.makeReadyHosts(6, hostFlavor.resources()).deployZoneApp(); + + ApplicationId app1 = tester.makeApplicationId("app1"); + ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); + + // Deploy with 1 group + tester.activate(app1, cluster1, Capacity.from(resources(4, 1, 10, 30, 10))); + assertEquals(4, tester.getNodes(app1, Node.State.active).size()); + assertEquals(4, tester.getNodes(app1, Node.State.active).group(0).size()); + assertEquals(0, tester.getNodes(app1, Node.State.active).group(0).retired().size()); + + // Split into 2 groups + tester.activate(app1, cluster1, Capacity.from(resources(4, 2, 10, 30, 10))); + assertEquals(6, tester.getNodes(app1, Node.State.active).size()); + assertEquals(4, tester.getNodes(app1, Node.State.active).group(0).size()); + assertEquals(2, tester.getNodes(app1, Node.State.active).group(0).retired().size()); + assertEquals(2, tester.getNodes(app1, Node.State.active).group(1).size()); + assertEquals(0, tester.getNodes(app1, Node.State.active).group(1).retired().size()); + } + + @Test + public void test_remove_group() { + Flavor hostFlavor = new Flavor(new NodeResources(20, 40, 100, 4)); + ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))) + .flavors(List.of(hostFlavor)) + .build(); + tester.makeReadyHosts(6, hostFlavor.resources()).deployZoneApp(); + + ApplicationId app1 = tester.makeApplicationId("app1"); + ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); + + // Deploy with 3 groups + tester.activate(app1, cluster1, Capacity.from(resources(6, 3, 10, 30, 10))); + assertEquals(6, tester.getNodes(app1, Node.State.active).size()); + assertEquals(0, tester.getNodes(app1, Node.State.active).retired().size()); + assertEquals(0, tester.getNodes(app1, Node.State.inactive).size()); + assertEquals(2, tester.getNodes(app1, Node.State.active).group(0).size()); + assertEquals(2, tester.getNodes(app1, Node.State.active).group(1).size()); + assertEquals(2, tester.getNodes(app1, Node.State.active).group(2).size()); + + // Remove a group + tester.activate(app1, cluster1, Capacity.from(resources(4, 2, 10, 30, 10))); + assertEquals(4, tester.getNodes(app1, Node.State.active).size()); + assertEquals(0, tester.getNodes(app1, Node.State.active).retired().size()); + assertEquals(2, tester.getNodes(app1, Node.State.inactive).size()); + assertEquals(2, tester.getNodes(app1, Node.State.active).group(0).size()); + assertEquals(2, tester.getNodes(app1, Node.State.active).group(1).size()); + assertEquals(0, tester.getNodes(app1, Node.State.active).group(2).size()); + } + + @Test + public void test_layout_change_to_fewer_groups() { + Flavor hostFlavor = new Flavor(new NodeResources(20, 40, 100, 4)); + ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))) + .flavors(List.of(hostFlavor)) + .build(); + tester.makeReadyHosts(12, hostFlavor.resources()).deployZoneApp(); + + ApplicationId app1 = tester.makeApplicationId("app1"); + ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); + + // Deploy with 3 groups + tester.activate(app1, cluster1, Capacity.from(resources(12, 4, 10, 30, 10))); + assertEquals(12, tester.getNodes(app1, Node.State.active).size()); + assertEquals( 0, tester.getNodes(app1, Node.State.active).retired().size()); + assertEquals( 0, tester.getNodes(app1, Node.State.inactive).size()); + assertEquals( 3, tester.getNodes(app1, Node.State.active).group(0).size()); + assertEquals( 3, tester.getNodes(app1, Node.State.active).group(1).size()); + assertEquals( 3, tester.getNodes(app1, Node.State.active).group(2).size()); + assertEquals( 3, tester.getNodes(app1, Node.State.active).group(3).size()); + + // Remove a group + tester.activate(app1, cluster1, Capacity.from(resources(12, 3, 10, 30, 10))); + assertEquals(12, tester.getNodes(app1, Node.State.active).size()); + assertEquals( 0, tester.getNodes(app1, Node.State.active).retired().size()); + assertEquals( 0, tester.getNodes(app1, Node.State.inactive).size()); + assertEquals( 4, tester.getNodes(app1, Node.State.active).group(0).size()); + assertEquals( 4, tester.getNodes(app1, Node.State.active).group(1).size()); + assertEquals( 4, tester.getNodes(app1, Node.State.active).group(2).size()); + assertEquals( 0, tester.getNodes(app1, Node.State.active).group(3).size()); + } + @Test public void test_provisioning_of_multiple_groups_after_flavor_migration_and_exiration() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); @@ -211,4 +306,8 @@ public class MultigroupProvisioningTest { return new HashSet<>(tester.prepare(application, cluster(), capacity)); } + private ClusterResources resources(int nodes, int groups, double vcpu, double memory, double disk) { + return new ClusterResources(nodes, groups, new NodeResources(vcpu, memory, disk, 0.1)); + } + } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/PrioritizableNodeTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/PrioritizableNodeTest.java index 1d9c135b4b5..3865baa51c1 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/PrioritizableNodeTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/PrioritizableNodeTest.java @@ -29,8 +29,8 @@ public class PrioritizableNodeTest { List<PrioritizableNode> expected = List.of( new PrioritizableNode(node("01", Node.State.ready), new NodeResources(2, 2, 2, 2), Optional.empty(), false, true, false, false), new PrioritizableNode(node("02", Node.State.active), new NodeResources(2, 2, 2, 2), Optional.empty(), true, false, false, false), - new PrioritizableNode(node("03", Node.State.inactive), new NodeResources(2, 2, 2, 2), Optional.empty(), true, false, false, false), new PrioritizableNode(node("04", Node.State.reserved), new NodeResources(2, 2, 2, 2), Optional.empty(), true, false, false, false), + new PrioritizableNode(node("03", Node.State.inactive), new NodeResources(2, 2, 2, 2), Optional.empty(), true, false, false, false), new PrioritizableNode(node("05", Node.State.ready), new NodeResources(2, 2, 2, 2), Optional.of(node("host1", Node.State.active)), true, false, true, false), new PrioritizableNode(node("06", Node.State.ready), new NodeResources(2, 2, 2, 2), Optional.of(node("host1", Node.State.ready)), true, false, true, false), new PrioritizableNode(node("07", Node.State.ready), new NodeResources(2, 2, 2, 2), Optional.of(node("host1", Node.State.provisioned)), true, false, true, false), diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java index 44688c61b34..03c07515cd5 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java @@ -486,40 +486,6 @@ public class ProvisioningTest { app1, cluster1); } - /** - * When increasing the number of groups without changing node count, we need to provison new nodes for - * the new groups since although we can remove nodes from existing groups without losing data we - * cannot do so without losing coverage. - */ - @Test - public void test_change_group_layout() { - Flavor hostFlavor = new Flavor(new NodeResources(20, 40, 100, 4)); - ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))) - .flavors(List.of(hostFlavor)) - .build(); - tester.makeReadyHosts(6, hostFlavor.resources()).deployZoneApp(); - - ApplicationId app1 = tester.makeApplicationId("app1"); - ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); - - // Deploy with 1 group - System.out.println("--- Deploying 1 group"); - tester.activate(app1, cluster1, Capacity.from(resources(4, 1, 10, 30, 10))); - assertEquals(4, tester.getNodes(app1, Node.State.active).size()); - assertEquals(4, tester.getNodes(app1, Node.State.active).group(0).size()); - assertEquals(0, tester.getNodes(app1, Node.State.active).group(0).retired().size()); - - // Split into 2 groups - System.out.println("--- Deploying 2 groups"); - tester.activate(app1, cluster1, Capacity.from(resources(4, 2, 10, 30, 10))); - assertEquals(6, tester.getNodes(app1, Node.State.active).size()); - assertEquals(4, tester.getNodes(app1, Node.State.active).group(0).size()); - assertEquals(2, tester.getNodes(app1, Node.State.active).group(0).retired().size()); - assertEquals(2, tester.getNodes(app1, Node.State.active).group(1).size()); - assertEquals(0, tester.getNodes(app1, Node.State.active).group(1).retired().size()); - } - - @Test(expected = IllegalArgumentException.class) public void prod_deployment_requires_redundancy() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java index c9d7e6bfa70..76b9c450557 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java @@ -256,7 +256,7 @@ public class ProvisioningTester { double vcpu, double memory, double disk, double bandwidth, DiskSpeed diskSpeed, StorageType storageType, ApplicationId app, ClusterSpec cluster) { - List<Node> nodeList = nodeRepository.list().owner(app).cluster(cluster.id()).not().retired().asList(); + List<Node> nodeList = nodeRepository.list().owner(app).cluster(cluster.id()).state(Node.State.active).not().retired().asList(); assertEquals(explanation + ": Node count", nodes, nodeList.size()); |