|
@@ -29,10 +29,12 @@ import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
|
|
+import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedList;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
|
+import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.Set;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
@@ -199,7 +201,10 @@ public class Balancer {
|
|
+ "\tWhether to run the balancer during an ongoing HDFS upgrade."
|
|
+ "\tWhether to run the balancer during an ongoing HDFS upgrade."
|
|
+ "This is usually not desired since it will not affect used space "
|
|
+ "This is usually not desired since it will not affect used space "
|
|
+ "on over-utilized machines."
|
|
+ "on over-utilized machines."
|
|
- + "\n\t[-asService]\tRun as a long running service.";
|
|
|
|
|
|
+ + "\n\t[-asService]\tRun as a long running service."
|
|
|
|
+ + "\n\t[-sortTopNodes]"
|
|
|
|
+ + "\tSort datanodes based on the utilization so "
|
|
|
|
+ + "that highly utilized datanodes get scheduled first.";
|
|
|
|
|
|
@VisibleForTesting
|
|
@VisibleForTesting
|
|
private static volatile boolean serviceRunning = false;
|
|
private static volatile boolean serviceRunning = false;
|
|
@@ -215,6 +220,7 @@ public class Balancer {
|
|
private final double threshold;
|
|
private final double threshold;
|
|
private final long maxSizeToMove;
|
|
private final long maxSizeToMove;
|
|
private final long defaultBlockSize;
|
|
private final long defaultBlockSize;
|
|
|
|
+ private final boolean sortTopNodes;
|
|
|
|
|
|
// all data node lists
|
|
// all data node lists
|
|
private final Collection<Source> overUtilized = new LinkedList<Source>();
|
|
private final Collection<Source> overUtilized = new LinkedList<Source>();
|
|
@@ -328,6 +334,7 @@ public class Balancer {
|
|
this.policy = p.getBalancingPolicy();
|
|
this.policy = p.getBalancingPolicy();
|
|
this.sourceNodes = p.getSourceNodes();
|
|
this.sourceNodes = p.getSourceNodes();
|
|
this.runDuringUpgrade = p.getRunDuringUpgrade();
|
|
this.runDuringUpgrade = p.getRunDuringUpgrade();
|
|
|
|
+ this.sortTopNodes = p.getSortTopNodes();
|
|
|
|
|
|
this.maxSizeToMove = getLongBytes(conf,
|
|
this.maxSizeToMove = getLongBytes(conf,
|
|
DFSConfigKeys.DFS_BALANCER_MAX_SIZE_TO_MOVE_KEY,
|
|
DFSConfigKeys.DFS_BALANCER_MAX_SIZE_TO_MOVE_KEY,
|
|
@@ -374,6 +381,8 @@ public class Balancer {
|
|
policy.accumulateSpaces(r);
|
|
policy.accumulateSpaces(r);
|
|
}
|
|
}
|
|
policy.initAvgUtilization();
|
|
policy.initAvgUtilization();
|
|
|
|
+ // Store the capacity % of over utilized nodes for sorting, if needed.
|
|
|
|
+ Map<Source, Double> overUtilizedPercentage = new HashMap<>();
|
|
|
|
|
|
// create network topology and classify utilization collections:
|
|
// create network topology and classify utilization collections:
|
|
// over-utilized, above-average, below-average and under-utilized.
|
|
// over-utilized, above-average, below-average and under-utilized.
|
|
@@ -383,7 +392,7 @@ public class Balancer {
|
|
final boolean isSource = Util.isIncluded(sourceNodes, dn.getDatanodeInfo());
|
|
final boolean isSource = Util.isIncluded(sourceNodes, dn.getDatanodeInfo());
|
|
for(StorageType t : StorageType.getMovableTypes()) {
|
|
for(StorageType t : StorageType.getMovableTypes()) {
|
|
final Double utilization = policy.getUtilization(r, t);
|
|
final Double utilization = policy.getUtilization(r, t);
|
|
- if (utilization == null) { // datanode does not have such storage type
|
|
|
|
|
|
+ if (utilization == null) { // datanode does not have such storage type
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -409,6 +418,7 @@ public class Balancer {
|
|
} else {
|
|
} else {
|
|
overLoadedBytes += percentage2bytes(thresholdDiff, capacity);
|
|
overLoadedBytes += percentage2bytes(thresholdDiff, capacity);
|
|
overUtilized.add(s);
|
|
overUtilized.add(s);
|
|
|
|
+ overUtilizedPercentage.put(s, utilization);
|
|
}
|
|
}
|
|
g = s;
|
|
g = s;
|
|
} else {
|
|
} else {
|
|
@@ -424,6 +434,10 @@ public class Balancer {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (sortTopNodes) {
|
|
|
|
+ sortOverUtilized(overUtilizedPercentage);
|
|
|
|
+ }
|
|
|
|
+
|
|
logUtilizationCollections();
|
|
logUtilizationCollections();
|
|
|
|
|
|
Preconditions.checkState(dispatcher.getStorageGroupMap().size()
|
|
Preconditions.checkState(dispatcher.getStorageGroupMap().size()
|
|
@@ -435,6 +449,21 @@ public class Balancer {
|
|
return Math.max(overLoadedBytes, underLoadedBytes);
|
|
return Math.max(overLoadedBytes, underLoadedBytes);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private void sortOverUtilized(Map<Source, Double> overUtilizedPercentage) {
|
|
|
|
+ Preconditions.checkState(overUtilized instanceof List,
|
|
|
|
+ "Collection overUtilized is not a List.");
|
|
|
|
+
|
|
|
|
+ LOG.info("Sorting over-utilized nodes by capacity" +
|
|
|
|
+ " to bring down top used datanode capacity faster");
|
|
|
|
+
|
|
|
|
+ List<Source> list = (List<Source>) overUtilized;
|
|
|
|
+ list.sort(
|
|
|
|
+ (Source source1, Source source2) ->
|
|
|
|
+ (Double.compare(overUtilizedPercentage.get(source2),
|
|
|
|
+ overUtilizedPercentage.get(source1)))
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
private static long computeMaxSize2Move(final long capacity, final long remaining,
|
|
private static long computeMaxSize2Move(final long capacity, final long remaining,
|
|
final double utilizationDiff, final long max) {
|
|
final double utilizationDiff, final long max) {
|
|
final double diff = Math.abs(utilizationDiff);
|
|
final double diff = Math.abs(utilizationDiff);
|
|
@@ -961,6 +990,10 @@ public class Balancer {
|
|
} else if ("-asService".equalsIgnoreCase(args[i])) {
|
|
} else if ("-asService".equalsIgnoreCase(args[i])) {
|
|
b.setRunAsService(true);
|
|
b.setRunAsService(true);
|
|
LOG.info("Balancer will run as a long running service");
|
|
LOG.info("Balancer will run as a long running service");
|
|
|
|
+ } else if ("-sortTopNodes".equalsIgnoreCase(args[i])) {
|
|
|
|
+ b.setSortTopNodes(true);
|
|
|
|
+ LOG.info("Balancer will sort nodes by" +
|
|
|
|
+ " capacity usage percentage to prioritize top used nodes");
|
|
} else {
|
|
} else {
|
|
throw new IllegalArgumentException("args = "
|
|
throw new IllegalArgumentException("args = "
|
|
+ Arrays.toString(args));
|
|
+ Arrays.toString(args));
|