前言
当集群规模在日益变大的时候,往往有的时候出现机器的老化,而这些“老化”的机器又会表现出一些奇怪的特征:“磁盘读写慢”、“网络数据传输慢”等。对于前者,曾经笔者写过一篇 Hadoop节点”慢磁盘”监控 的解决方案,当然社区目前已有更好的方案: HDFS-10959 ( Adding per disk IO statistics and metrics in DataNode )。而对于后者,我们同样需要有相应的监控方案,方便让我们这类异常的节点。此功能的实现于最近刚刚完成的 HDFS-11194 ( Maintain aggregated peer performance metrics on NameNode )。本文笔者来讲解讲解这个功能的设计思路以及它是如何做到对于“数据传输慢”节点的监控的。
HDFS“慢节点”监控的设计
HDFS“慢节点”监控分析功能的内部其实可以划分为2个部分。 第一个部分是监控数据的采集,这里监控数据对应的是网络数据传输的耗时。第二个则是监控数据的汇总处理。在这个过程中会进行一定的筛选比较,然后给出分析报告 。
与笔者之前提过的纯Metric统计方案有所不同,HDFS-11194在实现这个功能的时候,还定义了一个 SlowPeerReports 这样的对象,这个对象内部包含的数据就是“慢”节点的数据以及对应的耗时时间。先抛开这个slow report,如果是纯Metric的统计方案,有什么不好的地方呢?笔者认为有以下原因:
Metrics方便用户查阅,不方便用户获取其所包含的统计数据。
于是,在这里设计者定义来了SlowPeerReports对象老包装的这样的数据,然后作为心跳数据的一部分,发给NameNode。最终达到的目的是:用户可以通过简单的jmx接口就能获取这些慢节点的数据了。
下图是此功能的简单结构图。
!
图 1-1 HDFS”慢节点”监控功能结构图
HDFS”慢节点”监控功能的实现
数据的采集
正如上一部分所提到,这里的“慢”指的是“网络数据传输慢”。所以我们需要在HDFS数据传输的操作上做一个耗时统计,此处添加监控的位置在BlockReceiver的receivePacket方法。receivePacket方法的作用正如其名称所表示的意思:接收和处理数据包。代码如下:
private int receivePacket() throws IOException {
// read the next packet
packetReceiver.receiveNextPacket(in);
...
//First write the packet to the mirror:
if (mirrorOut != null && !mirrorError) {
try {
// 记住开始时间
long begin = Time.monotonicNow();
// For testing. Normally no-op.
DataNodeFaultInjector.get().stopSendingPacketDownstream(mirrorAddr);
packetReceiver.mirrorPacketTo(mirrorOut);
mirrorOut.flush();
// 获取目前时间
long now = Time.monotonicNow();
setLastSentTime(now);
// 计算数据传输耗时
long duration = now - begin;
DataNodeFaultInjector.get().logDelaySendingPacketDownstream(
mirrorAddr,
duration);
// 加入到metric统计中
trackSendPacketToLastNodeInPipeline(duration);
if (duration > datanodeSlowLogThresholdMs) {
LOG.warn(