diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index afa9d7c5ac5..04446f3bc0c 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -12,6 +12,8 @@ Release 2.0.3-alpha - Unreleased HDFS-3912. Detect and avoid stale datanodes for writes. (Jing Zhao via suresh) + HDFS-4059. Add number of stale DataNodes to metrics. (Jing Zhao via suresh) + IMPROVEMENTS HDFS-3925. Prettify PipelineAck#toString() for printing to a log diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeManager.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeManager.java index 18f120aafef..523d44227a8 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeManager.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeManager.java @@ -868,7 +868,7 @@ public class DatanodeManager { * @return Return the current number of stale DataNodes (detected by * HeartbeatManager). */ - int getNumStaleNodes() { + public int getNumStaleNodes() { return this.numStaleNodes; } diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java index 194b1a2c54d..d3653acbb8b 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java @@ -4662,6 +4662,13 @@ public class FSNamesystem implements Namesystem, FSClusterStats, public int getNumDeadDataNodes() { return getBlockManager().getDatanodeManager().getNumDeadDataNodes(); } + + @Override // FSNamesystemMBean + @Metric({"StaleDataNodes", + "Number of datanodes marked stale due to delayed heartbeat"}) + public int getNumStaleDataNodes() { + return getBlockManager().getDatanodeManager().getNumStaleNodes(); + } /** * Sets the generation stamp for this filesystem diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/metrics/FSNamesystemMBean.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/metrics/FSNamesystemMBean.java index d4033965dfb..b618cc64e16 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/metrics/FSNamesystemMBean.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/metrics/FSNamesystemMBean.java @@ -112,4 +112,10 @@ public interface FSNamesystemMBean { * @return number of dead data nodes */ public int getNumDeadDataNodes(); + + /** + * Number of stale data nodes + * @return number of stale data nodes + */ + public int getNumStaleDataNodes(); } diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockManagerTestUtil.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockManagerTestUtil.java index db84943791e..6a0b687f757 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockManagerTestUtil.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockManagerTestUtil.java @@ -191,4 +191,12 @@ public class BlockManagerTestUtil { "Must use default policy, got %s", bpp.getClass()); ((BlockPlacementPolicyDefault)bpp).setPreferLocalNode(prefer); } + + /** + * Call heartbeat check function of HeartbeatManager + * @param bm the BlockManager to manipulate + */ + public static void checkHeartbeat(BlockManager bm) { + bm.getDatanodeManager().getHeartbeatManager().heartbeatCheck(); + } } diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/metrics/TestNameNodeMetrics.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/metrics/TestNameNodeMetrics.java index 6fa0ed8a8b2..74ff4a4141a 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/metrics/TestNameNodeMetrics.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/metrics/TestNameNodeMetrics.java @@ -41,10 +41,14 @@ import org.apache.hadoop.hdfs.MiniDFSCluster; import org.apache.hadoop.hdfs.protocol.HdfsConstants.SafeModeAction; import org.apache.hadoop.hdfs.protocol.LocatedBlock; import org.apache.hadoop.hdfs.server.blockmanagement.BlockManager; +import org.apache.hadoop.hdfs.server.blockmanagement.BlockManagerTestUtil; +import org.apache.hadoop.hdfs.server.datanode.DataNode; +import org.apache.hadoop.hdfs.server.datanode.DataNodeTestUtils; import org.apache.hadoop.hdfs.server.namenode.FSNamesystem; import org.apache.hadoop.hdfs.server.namenode.NameNodeAdapter; import org.apache.hadoop.metrics2.MetricsRecordBuilder; import org.apache.hadoop.test.MetricsAsserts; +import org.apache.hadoop.util.Time; import org.apache.log4j.Level; import org.junit.After; import org.junit.Before; @@ -77,7 +81,8 @@ public class TestNameNodeMetrics { DFS_REPLICATION_INTERVAL); CONF.set(DFSConfigKeys.DFS_METRICS_PERCENTILES_INTERVALS_KEY, "" + PERCENTILES_INTERVAL); - + // Enable stale DataNodes checking + CONF.setBoolean(DFSConfigKeys.DFS_NAMENODE_CHECK_STALE_DATANODE_KEY, true); ((Log4JLogger)LogFactory.getLog(MetricsAsserts.class)) .getLogger().setLevel(Level.DEBUG); } @@ -125,6 +130,40 @@ public class TestNameNodeMetrics { stm.close(); } + /** Test metrics indicating the number of stale DataNodes */ + @Test + public void testStaleNodes() throws Exception { + // Set two datanodes as stale + for (int i = 0; i < 2; i++) { + DataNode dn = cluster.getDataNodes().get(i); + DataNodeTestUtils.setHeartbeatsDisabledForTests(dn, true); + long staleInterval = CONF.getLong( + DFSConfigKeys.DFS_NAMENODE_STALE_DATANODE_INTERVAL_KEY, + DFSConfigKeys.DFS_NAMENODE_STALE_DATANODE_INTERVAL_DEFAULT); + cluster.getNameNode().getNamesystem().getBlockManager() + .getDatanodeManager().getDatanode(dn.getDatanodeId()) + .setLastUpdate(Time.now() - staleInterval - 1); + } + // Let HeartbeatManager to check heartbeat + BlockManagerTestUtil.checkHeartbeat(cluster.getNameNode().getNamesystem() + .getBlockManager()); + assertGauge("StaleDataNodes", 2, getMetrics(NS_METRICS)); + + // Reset stale datanodes + for (int i = 0; i < 2; i++) { + DataNode dn = cluster.getDataNodes().get(i); + DataNodeTestUtils.setHeartbeatsDisabledForTests(dn, false); + cluster.getNameNode().getNamesystem().getBlockManager() + .getDatanodeManager().getDatanode(dn.getDatanodeId()) + .setLastUpdate(Time.now()); + } + + // Let HeartbeatManager to refresh + BlockManagerTestUtil.checkHeartbeat(cluster.getNameNode().getNamesystem() + .getBlockManager()); + assertGauge("StaleDataNodes", 0, getMetrics(NS_METRICS)); + } + /** Test metrics associated with addition of a file */ @Test public void testFileAdd() throws Exception {