diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java
index 8d9cd1c6caf1..b321d5cc2605 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java
@@ -410,7 +410,7 @@ public final class HddsConfigKeys {
public static final String HDDS_DATANODE_DISK_BALANCER_ENABLED_KEY =
"hdds.datanode.disk.balancer.enabled";
- public static final boolean HDDS_DATANODE_DISK_BALANCER_ENABLED_DEFAULT = false;
+ public static final boolean HDDS_DATANODE_DISK_BALANCER_ENABLED_DEFAULT = true;
public static final String HDDS_DATANODE_DNS_INTERFACE_KEY =
"hdds.datanode.dns.interface";
diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml b/hadoop-hdds/common/src/main/resources/ozone-default.xml
index b681e3bdd2e9..a7b62b1a298e 100644
--- a/hadoop-hdds/common/src/main/resources/ozone-default.xml
+++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml
@@ -218,11 +218,9 @@
hdds.datanode.disk.balancer.enabled
- false
+ true
OZONE, DATANODE, DISKBALANCER
- If this property is set to true, then the Disk Balancer
- feature is enabled on Datanodes, and users can use
- this service. By default, this is disabled.
+ By default Disk Balancer feature is enabled on Datanodes.
diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/diskbalancer/DiskBalancerService.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/diskbalancer/DiskBalancerService.java
index 1d065024dfb1..1d2c9ce86c75 100644
--- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/diskbalancer/DiskBalancerService.java
+++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/diskbalancer/DiskBalancerService.java
@@ -747,6 +747,7 @@ public static List buildVolumeReportProto(List -",
+ " Then type one datanode per line and end input:",
+ " - Linux/macOS: Ctrl-D",
+ " - Windows: Ctrl-Z, then Enter",
+ "Examples:",
+ " # Piped (recommended for scripts)",
+ " echo -e \"DN-1\\nDN-2\" | ozone admin datanode diskbalancer status -",
+ " # From file having list of dns to balance",
+ " ozone admin datanode diskbalancer report - < datanode-lists.txt",
+ "Port is optional and defaults to 19864 (CLIENT_RPC port).",
+ "Address examples: 'DN-1', 'DN-1:19864', '192.168.1.10'."
+ },
arity = "0..*",
paramLabel = "")
diff --git a/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/DiskBalancerCommands.java b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/DiskBalancerCommands.java
index c912ad735508..775f86c68489 100644
--- a/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/DiskBalancerCommands.java
+++ b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/DiskBalancerCommands.java
@@ -17,6 +17,8 @@
package org.apache.hadoop.hdds.scm.cli.datanode;
+import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DATANODE_DISK_BALANCER_ENABLED_KEY;
+
import org.apache.hadoop.hdds.cli.HddsVersionProvider;
import picocli.CommandLine.Command;
@@ -155,11 +157,10 @@
@Command(
name = "diskbalancer",
- description = "DiskBalancer specific operations. It is disabled by default." +
- " To enable it, set 'hdds.datanode.disk.balancer.enabled' as true",
+ description = "DiskBalancer specific operations to ensure even disk utilization." +
+ " It is enabled by default. Set " + HDDS_DATANODE_DISK_BALANCER_ENABLED_KEY + " to false to disable.",
mixinStandardHelpOptions = true,
versionProvider = HddsVersionProvider.class,
- hidden = true,
subcommands = {
DiskBalancerStartSubcommand.class,
DiskBalancerStopSubcommand.class,
diff --git a/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/DiskBalancerReportSubcommand.java b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/DiskBalancerReportSubcommand.java
index af730199ed8c..69ad560821d1 100644
--- a/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/DiskBalancerReportSubcommand.java
+++ b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/DiskBalancerReportSubcommand.java
@@ -23,6 +23,7 @@
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.hadoop.hdds.cli.HddsVersionProvider;
@@ -46,6 +47,8 @@ public class DiskBalancerReportSubcommand extends AbstractDiskBalancerSubCommand
private final Map reports =
new ConcurrentHashMap<>();
+ private static final String PERCENT_FORMAT = "%.2f%%";
+
@Override
protected Object executeCommand(String hostName) throws IOException {
DiskBalancerProtocol diskBalancerProxy = DiskBalancerSubCommandUtil
@@ -101,7 +104,8 @@ private String generateReport(List protos) {
StringBuilder header = new StringBuilder();
header.append("Datanode: ").append(dn).append(System.lineSeparator())
- .append("Aggregate VolumeDataDensity: ").append(p.getCurrentVolumeDensitySum())
+ .append("Aggregate VolumeDataDensity: ")
+ .append(formatPercent(p.getCurrentVolumeDensitySum()))
.append(System.lineSeparator());
if (p.hasIdealUsage() && p.hasDiskBalancerConf()
@@ -110,10 +114,11 @@ private String generateReport(List protos) {
double threshold = p.getDiskBalancerConf().getThreshold();
double lt = Math.max(0.0, idealUsage - threshold / 100.0);
double ut = Math.min(1.0, idealUsage + threshold / 100.0);
- header.append("IdealUsage: ").append(String.format("%.8f", idealUsage))
- .append(" | Threshold: ").append(threshold).append('%')
- .append(" | ThresholdRange: (").append(String.format("%.8f", lt))
- .append(", ").append(String.format("%.8f", ut)).append(')')
+ header.append("IdealUsage: ").append(formatPercent(idealUsage))
+ .append(" | Threshold: ")
+ .append(String.format(Locale.ROOT, PERCENT_FORMAT, threshold))
+ .append(" | ThresholdRange: (").append(formatPercent(lt))
+ .append(", ").append(formatPercent(ut)).append(')')
.append(System.lineSeparator())
.append(System.lineSeparator())
.append("Volume Details:").append(System.lineSeparator());
@@ -122,27 +127,29 @@ private String generateReport(List protos) {
contentList.add(header.toString());
if (p.getVolumeInfoCount() > 0 && p.hasIdealUsage()) {
- formatBuilder.append("%-45s %-40s %15s %15s %30s %20s %15s %15s%n");
+ formatBuilder.append("%-45s %-40s %15s %15s %15s %30s %20s %15s %15s%n");
contentList.add("StorageID");
contentList.add("StoragePath");
- contentList.add("TotalCapacity");
- contentList.add("UsedSpace");
- contentList.add("Container Pre-AllocatedSpace");
+ contentList.add("OzoneCapacity");
+ contentList.add("OzoneAvailable");
+ contentList.add("OzoneUsed");
+ contentList.add("ContainerPreAllocatedSpace");
contentList.add("EffectiveUsedSpace");
contentList.add("Utilization");
contentList.add("VolumeDensity");
double ideal = p.getIdealUsage();
for (VolumeReportProto v : p.getVolumeInfoList()) {
- formatBuilder.append("%-45s %-40s %15s %15s %30s %20s %15s %15s%n");
+ formatBuilder.append("%-45s %-40s %15s %15s %15s %30s %20s %15s %15s%n");
contentList.add(v.hasStorageId() ? v.getStorageId() : "-");
contentList.add(v.hasStoragePath() ? v.getStoragePath() : "-");
contentList.add(v.hasTotalCapacity() ? StringUtils.byteDesc(v.getTotalCapacity()) : "-");
+ contentList.add(v.hasOzoneAvailable() ? StringUtils.byteDesc(v.getOzoneAvailable()) : "-");
contentList.add(v.hasUsedSpace() ? StringUtils.byteDesc(v.getUsedSpace()) : "-");
contentList.add(StringUtils.byteDesc(v.getCommittedBytes()));
contentList.add(v.hasEffectiveUsedSpace() ? StringUtils.byteDesc(v.getEffectiveUsedSpace()) : "-");
- contentList.add(String.format("%.8f", v.getUtilization()));
- contentList.add(String.format("%.8f", Math.abs(v.getUtilization() - ideal)));
+ contentList.add(formatPercent(v.getUtilization()));
+ contentList.add(formatPercent(Math.abs(v.getUtilization() - ideal)));
}
formatBuilder.append("%n");
}
@@ -155,17 +162,21 @@ private String generateReport(List protos) {
formatBuilder.append("%nNote:%n")
.append(" - Aggregate VolumeDataDensity: Sum of per-volume density (deviation from ideal);")
.append(" higher means more imbalance.%n")
- .append(" - IdealUsage: Target utilization ratio (0-1) when volumes are evenly balanced.%n")
+ .append(" - IdealUsage: Target utilization (0-100%%) when volumes are evenly balanced.%n")
.append(" - ThresholdRange: Acceptable deviation (percent); volumes within")
.append(" IdealUsage +/- Threshold are considered balanced.%n")
.append(" - VolumeDensity: Deviation of a particular volume's utilization from IdealUsage.%n")
- .append(" - Utilization: Ratio of actual used space to capacity (0-1) for a particular volume.%n")
- .append(" - TotalCapacity: Total volume capacity.%n")
- .append(" - UsedSpace: Ozone used space.%n")
- .append(" - Container Pre-AllocatedSpace: Space reserved for containers not yet written to disk.%n")
+ .append(" - Utilization: how much a particular volume is utilized ")
+ .append("effectiveUsedSpace / ozoneCapacity) in %%.%n")
+ .append(" - OzoneCapacity: Ozone data volume capacity.%n")
+ .append(" - OzoneAvailable: Ozone data volume available space.%n")
+ .append(" - OzoneUsed: Ozone data volume used space.%n")
+ .append(" - ContainerPreAllocatedSpace: Space reserved for containers not yet written to disk.%n")
.append(" - EffectiveUsedSpace: This is the actual used space of volume which is visible")
.append(" to the diskBalancer : (ozoneCapacity minus ozoneAvailable) + containerPreAllocatedSpace + ")
- .append("move delta for source volume.%n");
+ .append("move delta.%n")
+ .append(" - move delta: source volume space to be reclaimed after move completion;" +
+ " this value is reflected only when diskBalancer is running else it is 0.%n");
return String.format(formatBuilder.toString(), contentList.toArray(new String[0]));
}
@@ -175,6 +186,10 @@ protected String getActionName() {
return "report";
}
+ private static String formatPercent(double ratio) {
+ return String.format(Locale.US, PERCENT_FORMAT, ratio * 100.0);
+ }
+
/**
* Create a JSON result map for a report.
*
@@ -186,7 +201,7 @@ private Map toJson(DatanodeDiskBalancerInfoProto report) {
result.put("datanode", DiskBalancerSubCommandUtil.getDatanodeHostAndIp(report.getNode()));
result.put("action", "report");
result.put("status", "success");
- result.put("volumeDensity", report.getCurrentVolumeDensitySum());
+ result.put("volumeDensity", formatPercent(report.getCurrentVolumeDensitySum()));
if (report.hasIdealUsage() && report.hasDiskBalancerConf()
&& report.getDiskBalancerConf().hasThreshold()) {
@@ -194,9 +209,10 @@ private Map toJson(DatanodeDiskBalancerInfoProto report) {
double threshold = report.getDiskBalancerConf().getThreshold();
double lt = Math.max(0.0, idealUsage - threshold / 100.0);
double ut = Math.min(1.0, idealUsage + threshold / 100.0);
- result.put("idealUsage", String.format("%.8f", idealUsage));
- result.put("threshold %", report.getDiskBalancerConf().getThreshold());
- result.put("thresholdRange", String.format("(%.08f, %.08f)", lt, ut));
+ result.put("idealUsage", formatPercent(idealUsage));
+ result.put("threshold %", String.format(Locale.ROOT, PERCENT_FORMAT, threshold));
+ result.put("thresholdRange", String.format("(%s, %s)",
+ formatPercent(lt), formatPercent(ut)));
}
if (report.getVolumeInfoCount() > 0) {
@@ -206,13 +222,14 @@ private Map toJson(DatanodeDiskBalancerInfoProto report) {
Map vm = new LinkedHashMap<>();
vm.put("storageId", v.getStorageId());
vm.put("storagePath", v.hasStoragePath() ? v.getStoragePath() : "-");
- vm.put("totalCapacity", v.hasTotalCapacity() ? StringUtils.byteDesc(v.getTotalCapacity()) : "-");
- vm.put("usedSpace", v.hasUsedSpace() ? StringUtils.byteDesc(v.getUsedSpace()) : "-");
+ vm.put("ozoneCapacity", v.hasTotalCapacity() ? StringUtils.byteDesc(v.getTotalCapacity()) : "-");
+ vm.put("ozoneAvailable", v.hasOzoneAvailable() ? StringUtils.byteDesc(v.getOzoneAvailable()) : "-");
+ vm.put("ozoneUsed", v.hasUsedSpace() ? StringUtils.byteDesc(v.getUsedSpace()) : "-");
vm.put("containerPreAllocatedSpace", StringUtils.byteDesc(v.getCommittedBytes()));
vm.put("effectiveUsedSpace", v.hasEffectiveUsedSpace() ?
StringUtils.byteDesc(v.getEffectiveUsedSpace()) : "-");
- vm.put("utilization", v.getUtilization());
- vm.put("volumeDensity", Math.abs(v.getUtilization() - ideal));
+ vm.put("utilization", formatPercent(v.getUtilization()));
+ vm.put("volumeDensity", formatPercent(Math.abs(v.getUtilization() - ideal)));
vols.add(vm);
}
diff --git a/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestDiskBalancerSubCommands.java b/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestDiskBalancerSubCommands.java
index e5a418fb0ae1..bd7a079eda73 100644
--- a/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestDiskBalancerSubCommands.java
+++ b/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestDiskBalancerSubCommands.java
@@ -22,7 +22,6 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -44,8 +43,6 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
-import org.apache.hadoop.hdds.HddsConfigKeys;
-import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.DiskBalancerProtocol;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
@@ -96,24 +93,18 @@ public void setup() throws UnsupportedEncodingException {
* Helper class to hold all mocks needed for DiskBalancer tests.
*/
private static class DiskBalancerMocks implements AutoCloseable {
- private final MockedConstruction mockedConf;
private final MockedConstruction mockedClient;
private final MockedStatic mockedUtil;
DiskBalancerMocks(
- MockedConstruction mockedConf,
MockedConstruction mockedClient,
MockedStatic mockedUtil) {
- this.mockedConf = mockedConf;
this.mockedClient = mockedClient;
this.mockedUtil = mockedUtil;
}
@Override
public void close() {
- if (mockedConf != null) {
- mockedConf.close();
- }
if (mockedClient != null) {
mockedClient.close();
}
@@ -128,14 +119,6 @@ public void close() {
* Returns a DiskBalancerMocks object containing all three mocks.
*/
private DiskBalancerMocks setupAllMocks() {
- MockedConstruction mockedConf =
- mockConstruction(OzoneConfiguration.class, (mock, context) -> {
- when(mock.getBoolean(
- eq(HddsConfigKeys.HDDS_DATANODE_DISK_BALANCER_ENABLED_KEY),
- eq(HddsConfigKeys.HDDS_DATANODE_DISK_BALANCER_ENABLED_DEFAULT)))
- .thenReturn(true);
- });
-
MockedConstruction mockedClient =
mockConstruction(ContainerOperationClient.class);
@@ -184,7 +167,7 @@ private DiskBalancerMocks setupAllMocks() {
return addressPort;
});
- return new DiskBalancerMocks(mockedConf, mockedClient, mockedUtil);
+ return new DiskBalancerMocks(mockedClient, mockedUtil);
}
@AfterEach
@@ -598,11 +581,11 @@ public void testStatusDiskBalancerWithStdin() throws Exception {
static Stream thresholdRangeReportCases() {
return Stream.of(
Arguments.of(0.08426521, 10.0, false,
- "ThresholdRange: (0.00000000, 0.18426521)", "ThresholdRange: (-"),
+ "ThresholdRange: (0.00%, 18.43%)", "ThresholdRange: (-"),
Arguments.of(0.95, 10.0, false,
- "ThresholdRange: (0.85000000, 1.00000000)", "1.05000000"),
+ "ThresholdRange: (85.00%, 100.00%)", "105.00%"),
Arguments.of(0.95, 10.0, true,
- "\"thresholdRange\" : \"(0.85000000, 1.00000000)\"", "1.05000000"));
+ "\"thresholdRange\" : \"(85.00%, 100.00%)\"", "105.00%"));
}
@ParameterizedTest(name = "idealUsage={0}, threshold={1}%, json={2}")
@@ -682,8 +665,9 @@ public void testReportDiskBalancerWithJson() throws Exception {
assertTrue(output.contains("\"volumes\""));
assertTrue(output.contains("\"storageId\""));
assertTrue(output.contains("\"storagePath\""));
- assertTrue(output.contains("\"totalCapacity\""));
- assertTrue(output.contains("\"usedSpace\""));
+ assertTrue(output.contains("\"ozoneCapacity\""));
+ assertTrue(output.contains("\"ozoneAvailable\""));
+ assertTrue(output.contains("\"ozoneUsed\""));
assertTrue(output.contains("\"effectiveUsedSpace\""));
assertTrue(output.contains("\"utilization\""));
assertTrue(output.contains("\"volumeDensity\""));
@@ -835,6 +819,8 @@ private DatanodeDiskBalancerInfoProto generateRandomReportProto(String hostname)
double util2 = idealUsage - random.nextDouble() * 0.1;
long used1 = (long) (capacity1 * util1);
long used2 = (long) (capacity2 * util2);
+ long available1 = capacity1 - used1;
+ long available2 = capacity2 - used2;
long effective1 = used1 + committed1;
long effective2 = used2 + committed2;
String path1 = "/data/hdds-" + hostname + "-1";
@@ -845,6 +831,7 @@ private DatanodeDiskBalancerInfoProto generateRandomReportProto(String hostname)
.setUtilization(util1)
.setCommittedBytes(committed1)
.setTotalCapacity(capacity1)
+ .setOzoneAvailable(available1)
.setUsedSpace(used1)
.setEffectiveUsedSpace(effective1)
.build();
@@ -854,6 +841,7 @@ private DatanodeDiskBalancerInfoProto generateRandomReportProto(String hostname)
.setUtilization(util2)
.setCommittedBytes(committed2)
.setTotalCapacity(capacity2)
+ .setOzoneAvailable(available2)
.setUsedSpace(used2)
.setEffectiveUsedSpace(effective2)
.build();
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/scm/node/TestDiskBalancer.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/scm/node/TestDiskBalancer.java
index 6df761e45f5a..cfdd4c7d37d7 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/scm/node/TestDiskBalancer.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/scm/node/TestDiskBalancer.java
@@ -32,7 +32,6 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.DatanodeDetails.Port;
@@ -71,7 +70,6 @@ public class TestDiskBalancer {
@BeforeAll
public static void setup() throws Exception {
ozoneConf = new OzoneConfiguration();
- ozoneConf.setBoolean(HddsConfigKeys.HDDS_DATANODE_DISK_BALANCER_ENABLED_KEY, true);
ozoneConf.setClass(ScmConfigKeys.OZONE_SCM_CONTAINER_PLACEMENT_IMPL_KEY,
SCMContainerPlacementCapacity.class, PlacementPolicy.class);
ozoneConf.setTimeDuration("hdds.datanode.disk.balancer.service.interval", 3, TimeUnit.SECONDS);
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/scm/node/TestDiskBalancerDuringDecommissionAndMaintenance.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/scm/node/TestDiskBalancerDuringDecommissionAndMaintenance.java
index 04c6273b8ae1..0bad66f87566 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/scm/node/TestDiskBalancerDuringDecommissionAndMaintenance.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/scm/node/TestDiskBalancerDuringDecommissionAndMaintenance.java
@@ -34,7 +34,6 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.DatanodeDetails.Port;
@@ -77,7 +76,6 @@ public class TestDiskBalancerDuringDecommissionAndMaintenance {
@BeforeAll
public static void setup() throws Exception {
conf = new OzoneConfiguration();
- conf.setBoolean(HddsConfigKeys.HDDS_DATANODE_DISK_BALANCER_ENABLED_KEY, true);
conf.setClass(ScmConfigKeys.OZONE_SCM_CONTAINER_PLACEMENT_IMPL_KEY,
SCMContainerPlacementCapacity.class, PlacementPolicy.class);
conf.setTimeDuration("hdds.datanode.disk.balancer.service.interval", 2, TimeUnit.SECONDS);