summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOla Aunrønning <olaa@verizonmedia.com>2019-07-26 17:15:23 +0200
committerOla Aunrønning <olaa@verizonmedia.com>2019-07-29 11:44:53 +0200
commit850bda1b8afb91f81170b664e8fcd82d1faa5c35 (patch)
tree4b296e01f826a0596816830547409beefde5a3c6
parent5d705fcb5eba5a6c394a86bd55165fb909ae98c2 (diff)
Refactoring resource metering
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshot.java71
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshotConsumer.java8
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockResourceSnapshotConsumer.java16
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java24
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java25
5 files changed, 94 insertions, 50 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshot.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshot.java
index 7f7a6b758d5..29c0948e828 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshot.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshot.java
@@ -1,27 +1,86 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.api.integration.resource;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeRepositoryNode;
+
import java.time.Instant;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* @author olaa
*/
public class ResourceSnapshot {
- private final ResourceAllocation resourceAllocation;
- private final Instant timestamp;
+ private ApplicationId applicationId;
+ private double cpuCores;
+ private double memoryGb;
+ private double diskGb;
+ private Instant timestamp;
- public ResourceSnapshot(ResourceAllocation resourceAllocation, Instant timestamp) {
- this.resourceAllocation = resourceAllocation;
+ public ResourceSnapshot(ApplicationId applicationId, double cpuCores, double memoryGb, double diskGb, Instant timestamp) {
+ this.applicationId = applicationId;
+ this.cpuCores = cpuCores;
+ this.memoryGb = memoryGb;
+ this.diskGb = diskGb;
this.timestamp = timestamp;
}
- public ResourceAllocation getResourceAllocation() {
- return resourceAllocation;
+ public static ResourceSnapshot from(List<NodeRepositoryNode> nodes, Instant timestamp) {
+ Set<ApplicationId> applicationIds = nodes.stream()
+ .map(n -> ApplicationId.from(n.getOwner().tenant, n.getOwner().application, n.getOwner().instance))
+ .collect(Collectors.toSet());
+
+ if (applicationIds.size() != 1) throw new IllegalArgumentException("List of nodes can only represent one application");
+
+ return new ResourceSnapshot(
+ applicationIds.iterator().next(),
+ nodes.stream().mapToDouble(NodeRepositoryNode::getMinCpuCores).sum(),
+ nodes.stream().mapToDouble(NodeRepositoryNode::getMinMainMemoryAvailableGb).sum(),
+ nodes.stream().mapToDouble(NodeRepositoryNode::getMinDiskAvailableGb).sum(),
+ timestamp
+ );
+ }
+
+ public ApplicationId getApplicationId() {
+ return applicationId;
+ }
+
+ public double getCpuCores() {
+ return cpuCores;
+ }
+
+ public double getMemoryGb() {
+ return memoryGb;
+ }
+
+ public double getDiskGb() {
+ return diskGb;
}
public Instant getTimestamp() {
return timestamp;
}
+ public void setApplicationId(ApplicationId applicationId) {
+ this.applicationId = applicationId;
+ }
+
+ public void setCpuCores(double cpuCores) {
+ this.cpuCores = cpuCores;
+ }
+
+ public void setMemoryGb(double memoryGb) {
+ this.memoryGb = memoryGb;
+ }
+
+ public void setDiskGb(double diskGb) {
+ this.diskGb = diskGb;
+ }
+
+ public void setTimestamp(Instant timestamp) {
+ this.timestamp = timestamp;
+ }
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshotConsumer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshotConsumer.java
index f7f3eddb482..bb6830770e2 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshotConsumer.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/ResourceSnapshotConsumer.java
@@ -1,9 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.api.integration.resource;
-import com.yahoo.config.provision.ApplicationId;
-
-import java.util.Map;
+import java.util.List;
/**
* Consumes a snapshot of resourses allocated/used per application.
@@ -12,5 +10,7 @@ import java.util.Map;
*/
public interface ResourceSnapshotConsumer {
- public void consume(Map<ApplicationId, ResourceSnapshot> resources);
+ public void consume(List<ResourceSnapshot> resources);
+
+ public List<ResourceSnapshot> getResourceSnapshots(String tenantName, String applicationName);
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockResourceSnapshotConsumer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockResourceSnapshotConsumer.java
index d5d7b63e933..2cd3aef1903 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockResourceSnapshotConsumer.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockResourceSnapshotConsumer.java
@@ -1,25 +1,29 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.api.integration.stubs;
-import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceSnapshot;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceSnapshotConsumer;
-import java.util.Map;
+import java.util.List;
/**
* @author olaa
*/
public class MockResourceSnapshotConsumer implements ResourceSnapshotConsumer {
- private Map<ApplicationId, ResourceSnapshot> resources;
+ private List<ResourceSnapshot> resources;
@Override
- public void consume(Map<ApplicationId, ResourceSnapshot> resources){
+ public void consume(List<ResourceSnapshot> resources){
this.resources = resources;
}
- public Map<ApplicationId, ResourceSnapshot> consumedResources() {
- return resources;
+ @Override
+ public List<ResourceSnapshot> getResourceSnapshots(String tenantName, String applicationName) {
+ throw new UnsupportedOperationException();
+ }
+
+ public List<ResourceSnapshot> consumedResources() {
+ return this.resources;
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java
index c1fa02a554c..6b9fdf475e0 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java
@@ -10,22 +10,17 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeReposi
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeOwner;
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeRepositoryNode;
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeState;
-import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceAllocation;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceSnapshot;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceSnapshotConsumer;
import java.time.Clock;
import java.time.Duration;
-import java.time.Instant;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Creates a ResourceSnapshot per application, which is then passed on to a ResourceSnapshotConsumer
- * TODO: Write JSON blob of node repo somewhere
*
* @author olaa
*/
@@ -57,22 +52,12 @@ public class ResourceMeterMaintainer extends Maintainer {
@Override
protected void maintain() {
List<NodeRepositoryNode> nodes = getNodes();
- Map<ApplicationId, ResourceAllocation> resourceAllocationByApplication = getResourceAllocationByApplication(nodes);
-
- // For now, we're only interested in resource allocation
- Instant timeStamp = clock.instant();
- Map<ApplicationId, ResourceSnapshot> resourceSnapshots = resourceAllocationByApplication.entrySet().stream()
- .collect(Collectors.toMap(
- e -> e.getKey(),
- e -> new ResourceSnapshot(e.getValue(), timeStamp))
- );
-
+ List<ResourceSnapshot> resourceSnapshots = getResourceSnapshots(nodes);
resourceSnapshotConsumer.consume(resourceSnapshots);
metric.set(metering_last_reported, clock.millis() / 1000, metric.createContext(Collections.emptyMap()));
- metric.set(metering_total_reported, resourceSnapshots.values().stream()
- .map(ResourceSnapshot::getResourceAllocation)
+ metric.set(metering_total_reported, resourceSnapshots.stream()
.mapToDouble(r -> r.getCpuCores() + r.getMemoryGb() + r.getDiskGb()) // total metered resource usage, for alerting on drastic changes
.sum()
, metric.createContext(Collections.emptyMap()));
@@ -88,11 +73,12 @@ public class ResourceMeterMaintainer extends Maintainer {
.collect(Collectors.toList());
}
- private Map<ApplicationId, ResourceAllocation> getResourceAllocationByApplication(List<NodeRepositoryNode> nodes) {
+ private List<ResourceSnapshot> getResourceSnapshots(List<NodeRepositoryNode> nodes) {
return nodes.stream()
.collect(Collectors.groupingBy(
node -> applicationIdFromNodeOwner(node.getOwner()),
- Collectors.collectingAndThen(Collectors.toList(), ResourceAllocation::from)));
+ Collectors.collectingAndThen(Collectors.toList(), nodeList -> ResourceSnapshot.from(nodeList, clock.instant()))
+ )).values().stream().collect(Collectors.toList());
}
private ApplicationId applicationIdFromNodeOwner(NodeOwner owner) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java
index 540efcba3b8..ad4511e7f11 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java
@@ -1,10 +1,8 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.maintenance;
-import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeRepositoryNode;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceSnapshot;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockResourceSnapshotConsumer;
import com.yahoo.vespa.hosted.controller.integration.NodeRepositoryClientMock;
@@ -13,10 +11,7 @@ import com.yahoo.vespa.hosted.controller.integration.ZoneApiMock;
import org.junit.Test;
import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
-import java.util.Map;
import static org.junit.Assert.*;
@@ -41,20 +36,20 @@ public class ResourceMeterMaintainerTest {
ResourceMeterMaintainer resourceMeterMaintainer = new ResourceMeterMaintainer(tester.controller(), Duration.ofMinutes(5), new JobControl(tester.curator()), nodeRepository, tester.clock(), metrics, snapshotConsumer);
resourceMeterMaintainer.maintain();
- Map<ApplicationId, ResourceSnapshot> consumedResources = snapshotConsumer.consumedResources();
+ List<ResourceSnapshot> consumedResources = snapshotConsumer.consumedResources();
+ // The mocked repository contains two applications, so we should also consume two ResourceSnapshots
assertEquals(2, consumedResources.size());
+ ResourceSnapshot app1 = consumedResources.stream().filter(snapshot -> snapshot.getApplicationId().equals(ApplicationId.from("tenant1", "app1", "default"))).findFirst().orElseThrow();
+ ResourceSnapshot app2 = consumedResources.stream().filter(snapshot -> snapshot.getApplicationId().equals(ApplicationId.from("tenant2", "app2", "default"))).findFirst().orElseThrow();
- ResourceSnapshot app1 = consumedResources.get(ApplicationId.from("tenant1", "app1", "default"));
- ResourceSnapshot app2 = consumedResources.get(ApplicationId.from("tenant2", "app2", "default"));
+ assertEquals(24, app1.getCpuCores(), DELTA);
+ assertEquals(24, app1.getMemoryGb(), DELTA);
+ assertEquals(500, app1.getDiskGb(), DELTA);
- assertEquals(24, app1.getResourceAllocation().getCpuCores(), DELTA);
- assertEquals(24, app1.getResourceAllocation().getMemoryGb(), DELTA);
- assertEquals(500, app1.getResourceAllocation().getDiskGb(), DELTA);
-
- assertEquals(40, app2.getResourceAllocation().getCpuCores(), DELTA);
- assertEquals(24, app2.getResourceAllocation().getMemoryGb(), DELTA);
- assertEquals(500, app2.getResourceAllocation().getDiskGb(), DELTA);
+ assertEquals(40, app2.getCpuCores(), DELTA);
+ assertEquals(24, app2.getMemoryGb(), DELTA);
+ assertEquals(500, app2.getDiskGb(), DELTA);
assertEquals(tester.clock().millis()/1000, metrics.getMetric("metering_last_reported"));
assertEquals(1112.0d, (Double) metrics.getMetric("metering_total_reported"), DELTA);