You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by ad...@apache.org on 2021/11/29 08:07:36 UTC
[ozone] branch master updated: HDDS-5897. Support configuration for including/excluding datanodes for balancing (#2786)
This is an automated email from the ASF dual-hosted git repository.
adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 7afd64f HDDS-5897. Support configuration for including/excluding datanodes for balancing (#2786)
7afd64f is described below
commit 7afd64f3d6a454a64b81015ec2d887e990634ae4
Author: Siddhant Sangwan <si...@gmail.com>
AuthorDate: Mon Nov 29 13:37:20 2021 +0530
HDDS-5897. Support configuration for including/excluding datanodes for balancing (#2786)
---
.../scm/container/balancer/ContainerBalancer.java | 25 ++++++++
.../balancer/ContainerBalancerConfiguration.java | 64 +++++++++++++++++++
.../container/balancer/TestContainerBalancer.java | 74 ++++++++++++++++++++++
3 files changed, 163 insertions(+)
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancer.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancer.java
index a234682..91dd1b2 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancer.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancer.java
@@ -77,6 +77,8 @@ public class ContainerBalancer {
private List<DatanodeUsageInfo> overUtilizedNodes;
private List<DatanodeUsageInfo> underUtilizedNodes;
private List<DatanodeUsageInfo> withinThresholdUtilizedNodes;
+ private Set<String> excludeNodes;
+ private Set<String> includeNodes;
private ContainerBalancerConfiguration config;
private ContainerBalancerMetrics metrics;
private long clusterCapacity;
@@ -242,6 +244,11 @@ public class ContainerBalancer {
}
return false;
}
+ this.excludeNodes = config.getExcludeNodes();
+ this.includeNodes = config.getIncludeNodes();
+ // include/exclude nodes from balancing according to configs
+ datanodeUsageInfos.removeIf(datanodeUsageInfo -> shouldExcludeDatanode(
+ datanodeUsageInfo.getDatanodeDetails()));
this.totalNodesInCluster = datanodeUsageInfos.size();
this.clusterCapacity = 0L;
@@ -668,6 +675,24 @@ public class ContainerBalancer {
}
/**
+ * Consults the configurations {@link ContainerBalancer#includeNodes} and
+ * {@link ContainerBalancer#excludeNodes} to check if the specified
+ * Datanode should be excluded from balancing.
+ * @param datanode DatanodeDetails to check
+ * @return true if Datanode should be excluded, else false
+ */
+ boolean shouldExcludeDatanode(DatanodeDetails datanode) {
+ if (excludeNodes.contains(datanode.getHostName()) ||
+ excludeNodes.contains(datanode.getIpAddress())) {
+ return true;
+ } else if (!includeNodes.isEmpty()) {
+ return !includeNodes.contains(datanode.getHostName()) &&
+ !includeNodes.contains(datanode.getIpAddress());
+ }
+ return false;
+ }
+
+ /**
* Updates conditions for balancing, such as total size moved by balancer,
* total size that has entered a datanode, and total size that has left a
* datanode in this iteration.
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerConfiguration.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerConfiguration.java
index a77c1b7..a0199e0 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerConfiguration.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerConfiguration.java
@@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -109,6 +110,20 @@ public final class ContainerBalancerConfiguration {
"iteration of Container Balancer.")
private long balancingInterval;
+ @Config(key = "include.datanodes", type = ConfigType.STRING, defaultValue =
+ "", tags = {ConfigTag.BALANCER}, description = "A list of Datanode " +
+ "hostnames or ip addresses separated by commas. Only the Datanodes " +
+ "specified in this list are balanced. This configuration is empty by " +
+ "default and is applicable only if it is non-empty.")
+ private String includeNodes = "";
+
+ @Config(key = "exclude.datanodes", type = ConfigType.STRING, defaultValue =
+ "", tags = ConfigTag.BALANCER, description = "A list of Datanode " +
+ "hostnames or ip addresses separated by commas. The Datanodes specified" +
+ " in this list are excluded from balancing. This configuration is empty" +
+ " by default.")
+ private String excludeNodes = "";
+
private DUFactory.Conf duConf;
/**
@@ -293,6 +308,55 @@ public final class ContainerBalancerConfiguration {
}
/**
+ * Gets a set of datanode hostnames or ip addresses that will be the exclusive
+ * participants in balancing.
+ * @return Set of hostname or ip address strings, or an empty set if the
+ * configuration is empty
+ */
+ public Set<String> getIncludeNodes() {
+ if (includeNodes.isEmpty()) {
+ return Collections.emptySet();
+ }
+ return Arrays.stream(includeNodes.split(","))
+ .map(String::trim)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Sets the datanodes that will be the exclusive participants in balancing.
+ * Applicable only if the specified string is non-empty.
+ * @param includeNodes a String of datanode hostnames or ip addresses
+ * separated by commas
+ */
+ public void setIncludeNodes(String includeNodes) {
+ this.includeNodes = includeNodes;
+ }
+
+ /**
+ * Gets a set of datanode hostnames or ip addresses that will be excluded
+ * from balancing.
+ * @return Set of hostname or ip address strings, or an empty set if the
+ * configuration is empty
+ */
+ public Set<String> getExcludeNodes() {
+ if (excludeNodes.isEmpty()) {
+ return Collections.emptySet();
+ }
+ return Arrays.stream(excludeNodes.split(","))
+ .map(String::trim)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Sets the datanodes that will be excluded from balancing.
+ * @param excludeNodes a String of datanode hostnames or ip addresses
+ * separated by commas
+ */
+ public void setExcludeNodes(String excludeNodes) {
+ this.excludeNodes = excludeNodes;
+ }
+
+ /**
* Gets the {@link OzoneConfiguration} using which this configuration was
* constructed.
* @return the {@link OzoneConfiguration} being used by this configuration
diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancer.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancer.java
index 314f378..e260bb3 100644
--- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancer.java
+++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancer.java
@@ -44,7 +44,9 @@ import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.ozone.test.GenericTestUtils;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -88,6 +90,9 @@ public class TestContainerBalancer {
new HashMap<>();
private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();
+ @Rule
+ public TemporaryFolder tempFolder = new TemporaryFolder();
+
/**
* Sets up configuration values and creates a mock cluster.
*/
@@ -525,6 +530,66 @@ public class TestContainerBalancer {
}
/**
+ * Tests if {@link ContainerBalancer} follows the includeNodes and
+ * excludeNodes configurations in {@link ContainerBalancerConfiguration}.
+ * If the includeNodes configuration is not empty, only the specified
+ * includeNodes should be included in balancing. excludeNodes should be
+ * excluded from balancing. If a datanode is specified in both include and
+ * exclude configurations, then it should be excluded.
+ */
+ @Test
+ public void balancerShouldFollowExcludeAndIncludeDatanodesConfigurations() {
+ balancerConfiguration.setThreshold(0.1);
+ balancerConfiguration.setIdleIteration(1);
+ balancerConfiguration.setMaxSizeEnteringTarget(10 * OzoneConsts.GB);
+ balancerConfiguration.setMaxSizeToMovePerIteration(100 * OzoneConsts.GB);
+ balancerConfiguration.setMaxDatanodesRatioToInvolvePerIteration(1.0);
+
+ // only these nodes should be included
+ // the ones also specified in excludeNodes should be excluded
+ int firstIncludeIndex = 0, secondIncludeIndex = 1;
+ int thirdIncludeIndex = nodesInCluster.size() - 2;
+ int fourthIncludeIndex = nodesInCluster.size() - 1;
+ String includeNodes =
+ nodesInCluster.get(firstIncludeIndex).getDatanodeDetails()
+ .getIpAddress() + ", " +
+ nodesInCluster.get(secondIncludeIndex).getDatanodeDetails()
+ .getIpAddress() + ", " +
+ nodesInCluster.get(thirdIncludeIndex).getDatanodeDetails()
+ .getHostName() + ", " +
+ nodesInCluster.get(fourthIncludeIndex).getDatanodeDetails()
+ .getHostName();
+
+ // these nodes should be excluded
+ int firstExcludeIndex = 0, secondExcludeIndex = nodesInCluster.size() - 1;
+ String excludeNodes =
+ nodesInCluster.get(firstExcludeIndex).getDatanodeDetails()
+ .getIpAddress() + ", " +
+ nodesInCluster.get(secondExcludeIndex).getDatanodeDetails()
+ .getHostName();
+
+ balancerConfiguration.setExcludeNodes(excludeNodes);
+ balancerConfiguration.setIncludeNodes(includeNodes);
+ containerBalancer.start(balancerConfiguration);
+ sleepWhileBalancing(500);
+ containerBalancer.stop();
+
+ // finally, these should be the only nodes included in balancing
+ // (included - excluded)
+ DatanodeDetails dn1 =
+ nodesInCluster.get(secondIncludeIndex).getDatanodeDetails();
+ DatanodeDetails dn2 =
+ nodesInCluster.get(thirdIncludeIndex).getDatanodeDetails();
+ for (Map.Entry<DatanodeDetails, ContainerMoveSelection> entry :
+ containerBalancer.getSourceToTargetMap().entrySet()) {
+ DatanodeDetails source = entry.getKey();
+ DatanodeDetails target = entry.getValue().getTargetNode();
+ Assert.assertTrue(source.equals(dn1) || source.equals(dn2));
+ Assert.assertTrue(target.equals(dn1) || target.equals(dn2));
+ }
+ }
+
+ /**
* Determines unBalanced nodes, that is, over and under utilized nodes,
* according to the generated utilization values for nodes and the threshold.
*
@@ -696,4 +761,13 @@ public class TestContainerBalancer {
.setBytesUsed(usedBytes)
.build();
}
+
+ private void sleepWhileBalancing(long millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException exception) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org