Apache Hadoop HDFS 监控

秦晓辉@快猫星云 2022年12月27日

HDFS 简介

Hadoop 体系包含很多大数据组件,很多组件都是以 HDFS 作为基础设施,HDFS 作为 GFS 的开源实现,对容灾的考虑非常到位,集群非常稳定,可以处理海量数据。HDFS 核心包含两个组件,一个是 NameNode,一个是 DataNode,NameNode 存储一些元信息,DataNode 则是存储具体数据块的节点。

对 HDFS 的监控,核心就是从 NameNode DataNode 中获取一些关键指标,而这俩组件都是 Java 写的,都通过 JMX 方式暴露监控指标,所以非常具有代表性。JMX 具体是个啥东西,请自行 Google,JMX 暴露的指标不好直接读取,一般通过 Jolokia 或者 jmx_exporter 进行封装,暴露为 HTTP 接口,这样监控系统直接从 HTTP 接口抓数据就可以了,非常方便。

Jolokia 简介

Jolokia 的主站 对 Jolokia 做了介绍。

Jolokia is remote JMX with JSON over HTTP. It is fast, simple, polyglot and has unique features. It’s JMX on Capsaicin. Jolokia is a JMX-HTTP bridge giving an alternative to JSR-160 connectors. It is an agent based approach with support for many platforms. In addition to basic JMX operations it enhances JMX remoting with unique features like bulk requests and fine grained security policies.

简单理解,Jolokia 就是一个 javaagent,javaagent 如果不知道是啥请自行 Google,在启动 NameNode 或者 DataNode 的时候,实际就是起了一个 java 进程,这个 java 进程可以接收很多参数,其中就有 -javaagent 参数,通过这个参数指定 Jolokia 的 jar 包地址以及端口等信息,Jolokia 就会在 NameNode、DataNode 的 JVM 中加载运行了,就可以读取 NameNode、DataNode 的 JMX 指标,然后通过 HTTP 接口暴露出来。

Jolokia 下载

去这个 Jolokia 下载页面,下载 jolokia-jvm-1.7.1.jar 这个 jar 包即可,姑且放到 /opt/jolokia 目录。

引入 Jolokia

需要在 NameNode、DataNode 中都引入 Jolokia,修改 etc/hadoop/hadoop-env.sh,导出如下变量:

JOLOKIAJAR="/opt/jolokia/jolokia-jvm-1.7.1.jar"
export HDFS_NAMENODE_OPTS="-javaagent:${JOLOKIAJAR}=port=7777,host=localhost"
export HDFS_DATANODE_OPTS="-javaagent:${JOLOKIAJAR}=port=7778,host=localhost"

之后 NameNode 就会暴露 7777 端口,DataNode 暴露 7778 端口,请求这俩端口的 /jolokia/version 接口即可获取到 Jolokia version 信息,如果能正常获取到 version 信息就说明安装正常。

采集数据

通过 Telegraf、Categraf 都可以采集 Jolokia 的数据,这里我们通过 Categraf 来采集,在 conf 目录下创建 input.jolokia_agent 目录,目录下创建 hdfs.toml 文件,hdfs.toml 文件的内容如下:

################
# NAMENODE     #
################
[[instances]]
  urls = ["http://localhost:7777/jolokia"]
  metrics_name_prefix = "hadoop_hdfs_namenode_"

  [[instances.metric]]
    name = "FSNamesystem"
    mbean = "Hadoop:name=FSNamesystem,service=NameNode"
    paths = ["CapacityTotal", "CapacityRemaining", "CapacityUsedNonDFS", "NumLiveDataNodes", "NumDeadDataNodes", "NumInMaintenanceDeadDataNodes", "NumDecomDeadDataNodes"]

  [[instances.metric]]
    name = "FSNamesystemState"
    mbean = "Hadoop:name=FSNamesystemState,service=NameNode"
    paths = ["VolumeFailuresTotal", "UnderReplicatedBlocks", "BlocksTotal"]
  
  [[instances.metric]]
    name = "OperatingSystem"
    mbean = "java.lang:type=OperatingSystem"
    paths = ["ProcessCpuLoad", "SystemLoadAverage", "SystemCpuLoad"]

  [[instances.metric]]
    name = "jvm_runtime"
    mbean = "java.lang:type=Runtime"
    paths = ["Uptime"]

  [[instances.metric]]
    name = "jvm_memory"
    mbean = "java.lang:type=Memory"
    paths = ["HeapMemoryUsage", "NonHeapMemoryUsage", "ObjectPendingFinalizationCount"]

  [[instances.metric]]
    name = "jvm_garbage_collector"
    mbean = "java.lang:name=*,type=GarbageCollector"
    paths = ["CollectionTime", "CollectionCount"]
    tag_keys = ["name"]

  [[instances.metric]]
    name = "jvm_memory_pool"
    mbean = "java.lang:name=*,type=MemoryPool"
    paths = ["Usage", "PeakUsage", "CollectionUsage"]
    tag_keys = ["name"]
    tag_prefix = "pool_"


################
# DATANODE     #
################
[[instances]]
  urls = ["http://localhost:7778/jolokia"]
  metrics_name_prefix = "hadoop_hdfs_datanode_"

  [[instances.metric]]
    name = "FSDatasetState"
    mbean = "Hadoop:name=FSDatasetState,service=DataNode"
    paths = ["Capacity", "DfsUsed", "Remaining", "NumBlocksFailedToUnCache", "NumBlocksFailedToCache", "NumBlocksCached"]

  [[instances.metric]]
    name = "OperatingSystem"
    mbean = "java.lang:type=OperatingSystem"
    paths = ["ProcessCpuLoad", "SystemLoadAverage", "SystemCpuLoad"]

  [[instances.metric]]
    name = "jvm_runtime"
    mbean = "java.lang:type=Runtime"
    paths = ["Uptime"]

  [[instances.metric]]
    name = "jvm_memory"
    mbean = "java.lang:type=Memory"
    paths = ["HeapMemoryUsage", "NonHeapMemoryUsage", "ObjectPendingFinalizationCount"]

  [[instances.metric]]
    name = "jvm_garbage_collector"
    mbean = "java.lang:name=*,type=GarbageCollector"
    paths = ["CollectionTime", "CollectionCount"]
    tag_keys = ["name"]

  [[instances.metric]]
    name = "jvm_memory_pool"
    mbean = "java.lang:name=*,type=MemoryPool"
    paths = ["Usage", "PeakUsage", "CollectionUsage"]
    tag_keys = ["name"]
    tag_prefix = "pool_"

在所有的 NameNode、DataNode 的机器上都要部署 Categraf,当然,有些机器上只有 DataNode,有些机器上既有 DataNode 也有 NameNode,上面的配置做相应调整即可。改完了配置之后可以通过下面的命令做个测试,看看是否正常收集到数据:

./categraf --test --inputs jolokia_agent

如果收集到数据就会在 stdout 打印出指标信息,最后重启 Categraf 或者发个 HUP 信号,完活。

总结

本文主要是介绍 NameNode 和 DataNode 的监控数据获取,采用的是 Jolokia 通过 JMX 拿到数据,其实还有别的方式可以获取监控数据,以后找机会再介绍。

关于作者

本文作者秦晓辉,快猫星云合伙人,文章内容是快猫技术团队共同沉淀的结晶,作者做了编辑整理,我们会持续输出监控、稳定性保障相关的技术文章,文章可转载,转载请注明出处,尊重技术人员的成果。

开源版
Flashcat
Flashduty