Skip to content

Commit e4b2801

Browse files
qijiale76jiajunmao
authored andcommitted
HDFS-17063. Support to configure different capacity reserved for each disk of DataNode. (apache#5793). Contributed by QI Jiale.
Reviewed-by : Tao Li <[email protected]> Signed-off-by: He Xiaoqiao <[email protected]>
1 parent 8bd9715 commit e4b2801

4 files changed

Lines changed: 104 additions & 18 deletions

File tree

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsVolumeImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ public class FsVolumeImpl implements FsVolumeSpi {
171171
this.usage = usage;
172172
if (this.usage != null) {
173173
reserved = new ReservedSpaceCalculator.Builder(conf)
174-
.setUsage(this.usage).setStorageType(storageType).build();
174+
.setUsage(this.usage).setStorageType(storageType)
175+
.setDir(currentDir != null ? currentDir.getParent() : "NULL").build();
175176
boolean fixedSizeVolume = conf.getBoolean(
176177
DFSConfigKeys.DFS_DATANODE_FIXED_VOLUME_SIZE_KEY,
177178
DFSConfigKeys.DFS_DATANODE_FIXED_VOLUME_SIZE_DEFAULT);

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/ReservedSpaceCalculator.java

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public static class Builder {
4646
private DF usage;
4747
private StorageType storageType;
4848

49+
private String dir;
50+
4951
public Builder(Configuration conf) {
5052
this.conf = conf;
5153
}
@@ -61,6 +63,11 @@ public Builder setStorageType(
6163
return this;
6264
}
6365

66+
public Builder setDir(String newDir) {
67+
this.dir = newDir;
68+
return this;
69+
}
70+
6471
ReservedSpaceCalculator build() {
6572
try {
6673
Class<? extends ReservedSpaceCalculator> clazz = conf.getClass(
@@ -69,10 +76,10 @@ ReservedSpaceCalculator build() {
6976
ReservedSpaceCalculator.class);
7077

7178
Constructor constructor = clazz.getConstructor(
72-
Configuration.class, DF.class, StorageType.class);
79+
Configuration.class, DF.class, StorageType.class, String.class);
7380

7481
return (ReservedSpaceCalculator) constructor.newInstance(
75-
conf, usage, storageType);
82+
conf, usage, storageType, dir);
7683
} catch (Exception e) {
7784
throw new IllegalStateException(
7885
"Error instantiating ReservedSpaceCalculator", e);
@@ -84,20 +91,30 @@ ReservedSpaceCalculator build() {
8491
private final Configuration conf;
8592
private final StorageType storageType;
8693

94+
private final String dir;
95+
8796
ReservedSpaceCalculator(Configuration conf, DF usage,
88-
StorageType storageType) {
97+
StorageType storageType, String dir) {
8998
this.usage = usage;
9099
this.conf = conf;
91100
this.storageType = storageType;
101+
this.dir = dir;
92102
}
93103

94104
DF getUsage() {
95105
return usage;
96106
}
97107

108+
String getDir() {
109+
return dir;
110+
}
111+
98112
long getReservedFromConf(String key, long defaultValue) {
99-
return conf.getLong(key + "." + StringUtils.toLowerCase(
100-
storageType.toString()), conf.getLongBytes(key, defaultValue));
113+
return conf.getLong(
114+
key + "." + getDir() + "." + StringUtils.toLowerCase(storageType.toString()),
115+
conf.getLong(key + "." + getDir(),
116+
conf.getLong(key + "." + StringUtils.toLowerCase(storageType.toString()),
117+
conf.getLongBytes(key, defaultValue))));
101118
}
102119

103120
/**
@@ -117,8 +134,8 @@ public static class ReservedSpaceCalculatorAbsolute extends
117134
private final long reservedBytes;
118135

119136
public ReservedSpaceCalculatorAbsolute(Configuration conf, DF usage,
120-
StorageType storageType) {
121-
super(conf, usage, storageType);
137+
StorageType storageType, String dir) {
138+
super(conf, usage, storageType, dir);
122139
this.reservedBytes = getReservedFromConf(DFS_DATANODE_DU_RESERVED_KEY,
123140
DFS_DATANODE_DU_RESERVED_DEFAULT);
124141
}
@@ -138,8 +155,8 @@ public static class ReservedSpaceCalculatorPercentage extends
138155
private final long reservedPct;
139156

140157
public ReservedSpaceCalculatorPercentage(Configuration conf, DF usage,
141-
StorageType storageType) {
142-
super(conf, usage, storageType);
158+
StorageType storageType, String dir) {
159+
super(conf, usage, storageType, dir);
143160
this.reservedPct = getReservedFromConf(
144161
DFS_DATANODE_DU_RESERVED_PERCENTAGE_KEY,
145162
DFS_DATANODE_DU_RESERVED_PERCENTAGE_DEFAULT);
@@ -162,8 +179,8 @@ public static class ReservedSpaceCalculatorConservative extends
162179
private final long reservedPct;
163180

164181
public ReservedSpaceCalculatorConservative(Configuration conf, DF usage,
165-
StorageType storageType) {
166-
super(conf, usage, storageType);
182+
StorageType storageType, String dir) {
183+
super(conf, usage, storageType, dir);
167184
this.reservedBytes = getReservedFromConf(DFS_DATANODE_DU_RESERVED_KEY,
168185
DFS_DATANODE_DU_RESERVED_DEFAULT);
169186
this.reservedPct = getReservedFromConf(
@@ -197,8 +214,8 @@ public static class ReservedSpaceCalculatorAggressive extends
197214
private final long reservedPct;
198215

199216
public ReservedSpaceCalculatorAggressive(Configuration conf, DF usage,
200-
StorageType storageType) {
201-
super(conf, usage, storageType);
217+
StorageType storageType, String dir) {
218+
super(conf, usage, storageType, dir);
202219
this.reservedBytes = getReservedFromConf(DFS_DATANODE_DU_RESERVED_KEY,
203220
DFS_DATANODE_DU_RESERVED_DEFAULT);
204221
this.reservedPct = getReservedFromConf(

hadoop-hdfs-project/hadoop-hdfs/src/main/resources/hdfs-default.xml

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,12 +397,19 @@
397397
<name>dfs.datanode.du.reserved</name>
398398
<value>0</value>
399399
<description>Reserved space in bytes per volume. Always leave this much space free for non dfs use.
400+
Specific directory based reservation is supported. The property can be followed with directory
401+
name which is set at 'dfs.datanode.data.dir'. For example, reserved space for /data/hdfs1/data
402+
can be configured using property 'dfs.datanode.du.reserved./data/hdfs1/data'. If specific directory
403+
reservation is not configured then dfs.datanode.du.reserved will be used.
400404
Specific storage type based reservation is also supported. The property can be followed with
401405
corresponding storage types ([ssd]/[disk]/[archive]/[ram_disk]/[nvdimm]) for cluster with heterogeneous storage.
402406
For example, reserved space for RAM_DISK storage can be configured using property
403407
'dfs.datanode.du.reserved.ram_disk'. If specific storage type reservation is not configured
404408
then dfs.datanode.du.reserved will be used. Support multiple size unit suffix(case insensitive),
405-
as described in dfs.blocksize.
409+
as described in dfs.blocksize. Use directory name and storage type based reservation at the
410+
same time is also allowed if both are configured.
411+
Property priority example: dfs.datanode.du.reserved./data/hdfs1/data.ram_disk >
412+
dfs.datanode.du.reserved./data/hdfs1/data > dfs.datanode.du.reserved.ram_disk > dfs.datanode.du.reserved
406413
Note: In case of using tune2fs to set reserved-blocks-percentage, or other filesystem tools,
407414
then you can possibly run into out of disk errors because hadoop will not check those
408415
external tool configurations.
@@ -414,12 +421,19 @@
414421
<value>0</value>
415422
<description>Reserved space in percentage. Read dfs.datanode.du.reserved.calculator to see
416423
when this takes effect. The actual number of bytes reserved will be calculated by using the
417-
total capacity of the data directory in question. Specific storage type based reservation
424+
total capacity of the data directory in question. Specific directory based reservation is
425+
supported. The property can be followed with directory name which is set at 'dfs.datanode.data.dir'.
426+
For example, reserved percentage space for /data/hdfs1/data can be configured using property
427+
'dfs.datanode.du.reserved.pct./data/hdfs1/data'. If specific directory reservation is not
428+
configured then dfs.datanode.du.reserved.pct will be used. Specific storage type based reservation
418429
is also supported. The property can be followed with corresponding storage types
419430
([ssd]/[disk]/[archive]/[ram_disk]/[nvdimm]) for cluster with heterogeneous storage.
420431
For example, reserved percentage space for RAM_DISK storage can be configured using property
421432
'dfs.datanode.du.reserved.pct.ram_disk'. If specific storage type reservation is not configured
422-
then dfs.datanode.du.reserved.pct will be used.
433+
then dfs.datanode.du.reserved.pct will be used. Use directory and storage type based reservation
434+
is also allowed if both are configured.
435+
Priority example: dfs.datanode.du.reserved.pct./data/hdfs1/data.ram_disk > dfs.datanode.du.reserved.pct./data/hdfs1/data
436+
> dfs.datanode.du.reserved.pct.ram_disk > dfs.datanode.du.reserved.pct
423437
</description>
424438
</property>
425439

hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/TestReservedSpaceCalculator.java

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,55 @@ public void testReservedSpaceAggresivePerStorageType() {
168168
checkReserved(StorageType.ARCHIVE, 100000, 5000);
169169
}
170170

171+
@Test
172+
public void testReservedSpaceAbsolutePerDir() {
173+
conf.setClass(DFS_DATANODE_DU_RESERVED_CALCULATOR_KEY, ReservedSpaceCalculatorAbsolute.class,
174+
ReservedSpaceCalculator.class);
175+
176+
String dir1 = "/data/hdfs1/data";
177+
String dir2 = "/data/hdfs2/data";
178+
String dir3 = "/data/hdfs3/data";
179+
180+
conf.setLong(DFS_DATANODE_DU_RESERVED_KEY + "." + dir1 + ".ssd", 900);
181+
conf.setLong(DFS_DATANODE_DU_RESERVED_KEY + "." + dir1, 1800);
182+
conf.setLong(DFS_DATANODE_DU_RESERVED_KEY + "." + dir2, 2700);
183+
conf.setLong(DFS_DATANODE_DU_RESERVED_KEY + ".ssd", 3600);
184+
conf.setLong(DFS_DATANODE_DU_RESERVED_KEY, 4500);
185+
186+
checkReserved(StorageType.SSD, 10000, 900, dir1);
187+
checkReserved(StorageType.DISK, 10000, 1800, dir1);
188+
checkReserved(StorageType.SSD, 10000, 2700, dir2);
189+
checkReserved(StorageType.DISK, 10000, 2700, dir2);
190+
checkReserved(StorageType.SSD, 10000, 3600, dir3);
191+
checkReserved(StorageType.DISK, 10000, 4500, dir3);
192+
}
193+
194+
@Test
195+
public void testReservedSpacePercentagePerDir() {
196+
conf.setClass(DFS_DATANODE_DU_RESERVED_CALCULATOR_KEY,
197+
ReservedSpaceCalculatorPercentage.class,
198+
ReservedSpaceCalculator.class);
199+
200+
String dir1 = "/data/hdfs1/data";
201+
String dir2 = "/data/hdfs2/data";
202+
String dir3 = "/data/hdfs3/data";
203+
204+
// Set percentage reserved values for different directories
205+
conf.setLong(DFS_DATANODE_DU_RESERVED_PERCENTAGE_KEY + "." + dir1 + ".ssd", 20);
206+
conf.setLong(DFS_DATANODE_DU_RESERVED_PERCENTAGE_KEY + "." + dir1, 10);
207+
conf.setLong(DFS_DATANODE_DU_RESERVED_PERCENTAGE_KEY + "." + dir2, 25);
208+
conf.setLong(DFS_DATANODE_DU_RESERVED_PERCENTAGE_KEY + ".ssd", 30);
209+
conf.setLong(DFS_DATANODE_DU_RESERVED_PERCENTAGE_KEY, 40);
210+
211+
// Verify reserved space calculations for different directories and storage types
212+
checkReserved(StorageType.SSD, 10000, 2000, dir1);
213+
checkReserved(StorageType.DISK, 10000, 1000, dir1);
214+
checkReserved(StorageType.SSD, 10000, 2500, dir2);
215+
checkReserved(StorageType.DISK, 10000, 2500, dir2);
216+
checkReserved(StorageType.SSD, 10000, 3000, dir3);
217+
checkReserved(StorageType.DISK, 10000, 4000, dir3);
218+
}
219+
171220
@Test(expected = IllegalStateException.class)
172221
public void testInvalidCalculator() {
173222
conf.set(DFS_DATANODE_DU_RESERVED_CALCULATOR_KEY, "INVALIDTYPE");
@@ -179,10 +228,15 @@ public void testInvalidCalculator() {
179228

180229
private void checkReserved(StorageType storageType,
181230
long totalCapacity, long reservedExpected) {
231+
checkReserved(storageType, totalCapacity, reservedExpected, "NULL");
232+
}
233+
234+
private void checkReserved(StorageType storageType,
235+
long totalCapacity, long reservedExpected, String dir) {
182236
when(usage.getCapacity()).thenReturn(totalCapacity);
183237

184238
reserved = new ReservedSpaceCalculator.Builder(conf).setUsage(usage)
185-
.setStorageType(storageType).build();
239+
.setStorageType(storageType).setDir(dir).build();
186240
assertEquals(reservedExpected, reserved.getReserved());
187241
}
188242
}

0 commit comments

Comments
 (0)