简介:这是一套专为Hadoop大数据平台运维与监控人员设计的Grafana可视化仪表盘资源,聚焦HDFS、YARN、HBase、Kafka等核心组件的实时性能观测与健康诊断,解决传统日志与命令行监控效率低、指标分散、难以快速定位瓶颈的问题。压缩包共14个文件,全部为可直接导入Grafana的JSON格式仪表盘配置文件,涵盖总览、HDFS(NameNode/DataNode)、YARN(ResourceManager/NodeManager)、HBase(HMaster/RegionServer)及Solr、EMQ、Prometheus等关联组件,结构清晰、模块独立,便于按需启用或组合部署;整体包体仅64KB,轻量易集成。已有373人学习下载,用户导入后只需对接已部署的Prometheus或JMX数据源,即可立即启用预调优的指标视图——包括存储利用率、任务队列长度、RPC延迟、GC耗时等关键维度,并支持基于阈值的告警联动与多层级下钻分析,显著降低定制化监控开发门槛。 我们组刚接手一个自建Hadoop集群的时候,第一周就把我搞失眠了。集群跑着十几个定时任务,HDFS上的数据源源不断落进来,YARN上几十个作业在排队。按说主机监控一直开着,CPU、内存、磁盘看着都挺正常,可偏偏某天凌晨NameNode进程悄悄挂了,监控大屏上所有主机指标都是绿的,跑批任务却集体失败,等到早上业务方找过来才知道出了问题。
这事儿的根子就在于:主机活着并不代表Hadoop服务活着。NameNode进程死了,机器却毫发无伤,你盯着CPU和内存怎么看都发现不了。从那之后我就下决心,一定要给Hadoop生态做一套真正能反映组件健康状态的监控Dashboard,让所有指标在Grafana上一目了然。这篇文章就把我搭这套从零到一的完整过程、技术选型和踩坑记录全部写出来,希望能给同样被Hadoop监控折磨的人一点参考。
1. Hadoop生态监控的痛点:为什么通用方案在这里会失灵
1.1 组件多、端口杂、指标口径不一
Hadoop从来不是单一组件,而是一个生态:HDFS负责存储,里面分NameNode和DataNode;YARN负责调度,有ResourceManager和NodeManager;往上还有HBase、Hive、ZooKeeper这些依赖件。每个组件都有自己独立的进程、独立的端口、独立的指标暴露方式。
你打开Hadoop的监控页面,NameNode上有500多MBean,DataNode上有200多个,YARN、HBase各自的MBean数量也不小。这些指标又不遵循同一个命名规范——HDFS告诉你CapacityUsed,YARN告诉你有多少ActiveApplications,HBase的指标叫RegionCount。组件之间虽然都有基于JMX的Metrics接口,但是面向终端用户的标准监控通道一直没有统一起来。
更麻烦的是端口。Hadoop 3.x版本里,NameNode的HTTP服务在9870端口,DataNode是9864,ResourceManager的WebUI在8088,NodeManager在8044。不同发行版、不同版本还可能不一样。你没法用一个固定的规则,把整个集群的指标全部收齐。要监控Hadoop,首先要面对的其实不是图表问题,而是指标采集的乱局。
1.2 商业方案与开源方案的取舍
市面上不是没有现成的方案。Cloudera Manager和Apache Ambari都自带完整的Hadoop监控,开箱即用,图表也很漂亮。但问题在于,很多公司集群是自己手动装的,所谓“裸Hadoop”,没有绑定任何商业发行版,这时候要引入CM或者Ambari,等于把整个集群的管理方式推翻重来,牵一发动全身。
另外还有一层考虑:这些管理平台本身就比较重,占资源不说,升级维护也要花不少精力。对一个运维团队来说,为了一套监控把底层集群改掉,风险收益比实在不划算。
所以更现实的选择是:基于现有的Prometheus+Grafana这套生态,把Hadoop各组件的JMX指标抓出来,自己组装Dashboard。这种方式对集群本身零侵入,只需要改一些JVM启动参数、部署几个exporter进程,就能把指标接进来。数据流打通之后,整个集群的状态用一套Grafana面板展示,故障定位、容量规划、性能分析都能在一个视图里完成。
2. 监控链路设计:从MBean到Grafana面板的数据流向
2.1 为什么选Prometheus这条链路
如果你去搜Hadoop监控相关资料,能看到很多种组合:Zabbix、Graphite、InfluxDB、Telegraf等等。但我实测下来,Prometheus+Grafana是个人和中小团队最顺手的一套。
Prometheus是拉模式采集,也就是说由Prometheus主动去各个exporter拉数据,不是agent往服务端推。这意味着什么?集群里加一台新节点,不用到服务端改配置,只要在Prometheus的targets列表里加一条记录就行。扩容、缩容都是这么简单。而且Prometheus自带标签体系,一个指标可以挂上host、role、cluster等任意维度的标签,画图时的筛选和聚合就非常灵活。
还有一点很关键:Grafana对Prometheus的PromQL有原生支持,不需要额外的适配层,图表拖动、阈值线、模板变量全部直接可用。如果换InfluxDB,图表查询语言要写成Flux,和PromQL差异很大,等于把简单问题复杂化了。
2.2 链路各环节的职责拆分
整套链路每个环节只干一件事,职责分得很清楚:
- Hadoop各组件通过JMX暴露MBean,这是数据源头;
- jmx_exporter负责把JMX指标取出来,转成Prometheus的metric格式,暴露一个HTTP端口;
- Prometheus按照配置的抓取频率,定期去exporter拉取指标,存入本地时序数据库;
- Grafana通过PromQL从Prometheus查询数据,绘制成Dashboard,并承担告警规则的触发。
你可以把这条链路类比成自来水管:Hadoop的JMX是水源头,jmx_exporter是水龙头上的接头,Prometheus是蓄水池和泵站,Grafana就是你家里的水龙头。任何一个环节堵塞,最终到你眼前的水流都会出问题。
实际部署的时候,jmx_exporter又分两种用法。一种是jmx_prometheus_javaagent,作为Java Agent直接挂到Hadoop进程里,JVM启动的时候带上-javaagent参数即可。另一种是独立的jmx_exporter进程,通过JMX RMI协议去远程连接Hadoop进程。这两种我实测都跑过,各有利弊。
Java Agent方式部署简单,不需要额外管理一个进程,但每次Hadoop进程重启,exporter也一起重启了,而且如果agent配置写错了,可能影响Hadoop本身的启动。独立jmx_exporter方式对Hadoop进程零侵入,出问题也不影响集群,就是需要自己用systemd把它管起来。我自己更倾向独立方式,集群稳定优先,多管几个进程完全不是问题。
3. 实操第一步:把HDFS的指标完整捞上来
3.1 开启远程JMX并部署jmx_exporter
HDFS的监控要从NameNode和DataNode上下手。先给NameNode开启远程JMX。这里以Hadoop 3.x为例,编辑hadoop-env.sh,找到HADOOP_NAMENODE_OPTS这一行,往里面追加JMX参数:
export HADOOP_NAMENODE_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.rmi.port=9011 -Djava.rmi.server.hostname=node01 $HADOOP_NAMENODE_OPTS"这里有两个细节容易踩坑。
第一,com.sun.management.jmxremote.port和com.sun.management.jmxremote.rmi.port是两回事,前者是JMX连接端口,后者是RMI数据交换端口。如果集群有防火墙,而你把RMI端口设成动态随机分配,很可能出现“客户端能连上但拿不到数据”的情况。所以最好把两个端口都固定下来,统一在防火墙放行。
第二,java.rmi.server.hostname必须设置成其他机器能访问到的地址,不能留空。否则jmx_exporter从别的机器连接时,拿到的是Hadoop进程自己认为的主机名,很可能连接失败或超时。
接下来下载jmx_exporter:
wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_httpserver/0.20.0/jmx_prometheus_httpserver-0.20.0-jar-with-dependencies.jar -O /opt/jmx_exporter/jmx_prometheus_httpserver.jar然后写exporter的抓取配置。这里的关键是,不是把所有MBean都一股脑转出来,那样指标爆炸,Prometheus存储压力大,看图也没意义。我是建议先按需去取。初始阶段可以先把NameNode的HDFS存储指标取出来,配置文件按下面的方式写:
rules: - pattern: 'Hadoop:service=NameNode,name=FSNamesystemState*' - pattern: 'Hadoop:service=NameNode,name=FSNamesystem*' - pattern: 'Hadoop:service=NameNode,name=CapacityTotal' - pattern: 'Hadoop:service=NameNode,name=CapacityUsed' - pattern: 'Hadoop:service=NameNode,name=CapacityRemaining' - pattern: 'Hadoop:service=NameNode,name=BlockStates*'具体MBean字段,你可以先打开NameNode的JMX页面看一眼再定。Hadoop 3.x的NameNode Web UI端口是9870,地址是http://node01:9870/jmx,会返回一大串JSON,搜一下对应的对象就能确认名字。
配置保存后启动exporter:
java -jar /opt/jmx_exporter/jmx_prometheus_httpserver.jar 9101 /opt/jmx_exporter/namenode.yml这样一个独立的jmx_exporter就起来了,监听9101端口,输出Prometheus格式的指标。DataNode同理,只是JMX端口换成9012,exporter监听端口换成9102。
3.2 Prometheus采集任务与标签规整
Prometheus这边要新增采集任务。编辑prometheus.yml,在scrape_configs里追加:
- job_name: 'hdfs-namenode' static_configs: - targets: ['node01:9101'] labels: role: 'namenode' cluster: 'prod' - job_name: 'hdfs-datanode' static_configs: - targets: ['node01:9102', 'node02:9102', 'node03:9102'] labels: role: 'datanode' cluster: 'prod'这里我自己习惯给每个target打上role和cluster标签。原因是同一个jmx_exporter配置可能同时用在多个集群上,没有这个标签,绘图时几个集群的数据会混在一起,你就没法单独看某一套集群的状态了。
配置好之后重启Prometheus,在Targets页面就能看到这两个任务是UP状态。如果显示DOWN,顺着地址排查exporter进程是否在跑,防火墙是否放行。
3.3 导入仪表盘并验证关键指标
Prometheus采集正常后,就可以去Grafana创建Dashboard了。
如果你不想从零画,Grafana官网的Dashboards列表里直接搜“Hadoop”,能找到不少社区分享的面板。我推荐先导入一份ID为12769的HDFS Dashboard(具体ID可能随时间变化,请在官方页面确认),然后基于它改。但要注意,社区模板很多用的是别人的exporter配置和job名,导入后大概率一片红,需要把每个面板的查询改成你自己的job名。
如果你倾向于自己画,核心指标至少要包含这几个维度:
- HDFS容量:
hadoop_namenode_capacity_total、hadoop_namenode_capacity_used、hadoop_namenode_capacity_remaining; - 数据块状态:
hadoop_namenode_blockstates_pending_replication_blocks、hadoop_namenode_blockstates_corrupt_blocks; - DataNode存活:通过
up{job="hdfs-datanode"}判断; - 文件读写量:按时间做
rate()计算,看流量趋势。
验证指标是否采到的办法很简单,在Grafana面板的Query里写一句:
hadoop_namenode_capacity_used如果图表有数据出来,说明整条链路通了。看到数据在跳的那一瞬间,我整个人都很踏实——之前那种“主机全绿但服务挂了”的焦虑一下子消失了,因为现在看到的每一块数据都来自Hadoop进程本身。
4. YARN与HBase的差异化监控:同样的方法,不同的关注点
4.1 YARN:队列资源和应用状态的指标
HDFS搞通之后,YARN的监控是同样的套路,但关注点完全不一样。YARN的关键在于ResourceManager和NodeManager。
ResourceManager有这些指标特别值得盯:
ActiveApplications:当前活跃的应用数量,快速判断集群负载;PendingContainers:等待分配的Container数量,这个值持续升高说明集群资源饱和;AvailableMB:可用内存,看资源池是否被占满;- 各个队列的
AllocatedMB、PendingMB,这个配合Capacity Scheduler做多队列隔离时特别关键; LostNodes、UnhealthyNodes,这个与节点健康检查直接相关,节点闹情绪的时候这个值会跳。
NodeManager的指标则要看单机视角:运行中的Container数量、分配的内存和CPU、本地日志占用。这些指标可以帮助你判断某台机器是不是资源分配不均衡。
配置上,启用ResourceManager的JMX参数改YARN_RESOURCEMANAGER_OPTS,NodeManager改YARN_NODEMANAGER_OPTS,然后各挂一个独立的jmx_exporter。exporter的配置文件按需抓取即可。目标端采集写进Prometheus:
- job_name: 'yarn-resourcemanager' static_configs: - targets: ['node01:9111'] labels: role: 'resourcemanager' cluster: 'prod'4.2 HBase:读写延迟与Region平衡
HBase的监控相比YARN更细致,因为它是直接面向在线业务的存储引擎,读写延迟、Region分布、MemStore大小这些指标直接决定了业务的响应效果。
RegionServer上重点看:
ServerReadRequestsPerSecond和ServerWriteRequestsPerSecond:读写速率;RegionCount:Region数量,注意是否分配均衡,有些RegionServer Region数远超其他节点就容易产生热点;MemStoreSize:MemStore大小,如果某个RegionServer的MemStore占用持续偏高,说明Flush不及时,可能有大Region或写入压力异常;BlockCacheHitRatio:块缓存命中率,低了要检查读热点和BlockCache大小。
HMaster上则关注MasterActiveTime、MasterStartTime这种基础指标,以及RegionServer是否都正常注册。
HBase的JMX端口配置跟前面一样,改HBASE_REGIONSERVER_OPTS和HBASE_MASTER_OPTS。RegionServer的metrics相对多,exporter的配置尽量按需要的字段去筛,不要全量采集。
4.3 ZooKeeper、Hive等的监控补充
ZooKeeper虽然本身不是Hadoop组件,但HDFS HA和HBase都依赖它。ZooKeeper的上层应用挂了,大家都很难察觉。ZooKeeper的监控和别的不太一样,因为它不是纯Java进程的JMX方式,还有自己的一套四字命令协议,比如ruok、mntr。配合zookeeper_exporter可以很方便地拿到指标:
- job_name: 'zookeeper' static_configs: - targets: ['node01:2182', 'node02:2182', 'node03:2182']重点看ZooKeeper的znode_count、watch_count、outstanding_requests,以及连接的客户端数量。outstanding_requests如果持续偏高,说明ZooKeeper处理不过来,HBase和HDFS HA都会出问题。
Hive的监控没那么标准,HiveServer2本身没有特别完善的Metrics接口。我的做法是分两步:HiveServer2的进程存活用JMX基本指标判断;更精确的查询性能、执行时长,则接日志或者通过beeline执行结果侧面观察。如果你用的是Hive on Tez,还要同时盯Tez的ApplicationMaster运行状态。这一块没有一劳永逸的模板,得结合自己集群的任务特征来定。
5. 告警配置:让Dashboard主动替你盯夜班
5.1 告警规则设计原则与样例规则
Dashboard做得再好看,也不可能24小时盯着看。真正让监控有价值的是告警——出问题的时候有消息主动找到你。
我自己的告警设计原则是三句话:先保活,再保容量,最后保性能。
保活是最基础的一层。任何核心进程挂了必须立刻通知。用Prometheus自带的up指标就能判断:
groups: - name: hadoop-core-alerts rules: - alert: NameNodeProcessDown expr: up{job="hdfs-namenode"} == 0 for: 2m labels: severity: critical annotations: summary: "NameNode进程不可用" description: "主机 {{ $labels.instance }} 的NameNode进程已宕机 { for: 2m } 分钟"注意这个for: 2m的延时,我的经验是不要设成0。Hadoop在做滚动重启的时候进程会短暂消失,如果你一秒钟内就把告警发出去了,会收到大量误报。设成2分钟可以过滤掉这类正常维护窗口。
容量告警是Hadoop运维里最容易遗忘的。HDFS磁盘写满时,所有写入任务都会失败,而且恢复非常费劲。所以我给HDFS容量和NameNode的SafeMode状态都加了告警:
- alert: HDFSCapacityLow expr: (hadoop_namenode_capacity_remaining / hasoop_namenode_capacity_total) * 100 < 10 for: 10m labels: severity: warning annotations: summary: "HDFS容量不足" description: "HDFS剩余空间已低于10%,当前剩余比例:{{ $value | humanizePercentage }}"这里的10可以是任意阈值,但如果你觉得10%才告警太晚,建议拆成两个规则:剩余低于30%发warning,低于10%发critical。提前预警,给运维留出做数据清理或扩容的时间。
5.2 数据源级告警与Grafana通知策略
Prometheus里的告警规则只是第一步,还需要把告警事件发到通知渠道。
一种方式是传统的Alertmanager+Prometheus:Prometheus把告警推给Alertmanager,Alertmanager再负责路由、去重、发到钉钉、邮件或者Slack。这套适合告警量大、要精细管理的场景。
如果你不想维护Alertmanager,Grafana本身也支持直接配置告警。Grafana 9以后把告警功能收编进统一告警中心,可以直接在Dashboard面板上创建AlertRule。它的规则基于面板查询,一旦阈值触发,就能通过内置的“Notification policies”发到钉钉、邮件等渠道。
我个人比较推荐先用Grafana自带的告警,尤其是中小集群的运维场景。理由很简单:Grafana的告警规则和Dashboard绑定在一起,图表上画的是什么,告警就在什么条件上触发,直观且容易理解。Alertmanager的功能更强大,但对于一个几十台机器规模的集群,Grafana自带告警已经足够,不用多维护一个组件。
配置告警还有一个细节:查询表达式最好带上rate()或irate()后再比较,否则像读写请求量这类计数器指标,数据一直在涨,你拿原始值和阈值比怎么比都不对。比如:
rate(hadoop_namenode_blockstates_pending_replication_blocks[5m]) > 0这样看的是5分钟内的速率变化,才符合“复制请求积压”这个告警语义。
6. 真实的坑与排错记录:从“连不上”到“图全红”
6.1 JMX连接失败排查链路
这套监控搭建过程中,我踩得最多的坑就是“Prometheus能访问exporter,但exporter访问Hadoop的JMX失败”。
最典型的报错是Connection refused或者java.rmi.ConnectException。碰到这类问题,先不要怀疑prometheus.yml写错了,而是先用命令行验证JMX端口通不通:
telnet node01 9010如果端口不通,多半是防火墙没放行。把9010和9011两个端口都加上。
如果端口通,仍然连接失败,排查方向就转向RMI。上面说过要设置java.rmi.server.hostname,这里我再强调一次:Hadoop进程如果跑在容器里或者主机名解析有问题,不设置这个参数,exporter拿到的是内网容器IP而不是宿主机IP,你会发现本机能连,跨机器就断。这个参数记得配成exporter机器能访问到的稳定地址。
还有一个隐蔽的坑:有些发行版的Hadoop在启动时会用JAVA_TOOL_OPTIONS覆盖HADOOP_XXX_OPTS里的JMX配置。你明明改好了hadoop-env.sh,进程起来却没有监听9010端口。排查方法是看进程启动参数:
ps -ef | grep NameNode | grep java确认命令行里是否带上了-Dcom.sun.management.jmxremote.port=9010。没有的话就是配置被覆盖了,需要追一下HADOOP_NAMENODE_OPTS变量最终的取值。
6.2 指标名对不上:命名空间与标签的坑
jmx_exporter配置好之后,最烦人的问题是:我以为会生成hadoop_namenode_capacity_total这个指标,结果在Prometheus里怎么都查不到。
原因在jmx_exporter对MBean的名字做了转换:Hadoop:service=NameNode,name=CapacityTotal会被转换成hadoop_namenode_capacity_total。中间的冒号、等号、逗号都会被转成下划线。问题在于,MBean的名字里还可能有版本号之类的干扰项,转换结果跟你预想不完全一样。
解决办法很笨但很有效:直接看exporter暴露的HTTP接口。curl一下exporter的端口:
curl -s http://node01:9101/metrics | grep Capacity看看实际生成的指标名、标签名叫什么,按照实际的名字去写Dashboard查询。不要凭记忆写指标名,一切以实际输出为准。
命名空间也是一样。如果Hadoop集群里跑了多个namespace或备份集群,MBean名字里会带namespace标签,比如Hadoop:service=NameNode,name=FSNamesystemState,namespace=ns1。你会发现同样的指标在Prometheus里出现了多个不同的标签组合,画图的时候记得按namespace筛选,免得把两个集群的数据合并起来看。
6.3 仪表盘导入即全红:采集路线的常见断点
从Grafana官网导入社区模板后,面板一片红是家常便饭。主要原因有三个:
第一,模板用的数据源名和你Grafana里创建的不一致。比如模板里写的是Prometheus-1,你创建的数据源叫Prometheus,查询不到数据自然全红。导入时在参数设置页面把数据源换成你实际创建的即可。
第二,模板里的PromQL用到的指标名和实际不一致。模板作者可能用的是他的Hadoop发行版指标名,而你的是Apache Hadoop,命名有差异。这种就要逐个面板改查询,或者干脆以模板为参考自己重新画。
第三,模板里的job标签和你的不匹配。这种需要先找到模板中用了哪个job名,然后调整你Prometheus里的job_name,或者改Dashboard的模板变量筛选条件。
我建议的做法是不要“导入模板就完事”。把模板当作参考,自己过一遍每个面板,把不合适的查询改掉。整个过程等于把自己的集群指标翻了一遍,之后哪里有问题心里清楚得很。
6.4 多exporter进程管理:systemd统一守护
集群规模上来之后,机器数量多,每个节点上挂多个exporter进程,单纯用nohup java -jar方式启动,进程挂了也没人管,监控本身反而成了新的故障点。所以每个exporter都必须交给systemd管理。
下面是一个jmx_exporter的systemd unit文件示例:
[Unit] Description=JMX Exporter for NameNode After=network.target [Service] ExecStart=/usr/bin/java -jar /opt/jmx_exporter/jmx_prometheus_httpserver.jar 9101 /opt/jmx_exporter/namenode.yml User=hdfs Restart=always RestartSec=10 [Install] WantedBy=multi-user.target把unit文件放到/etc/systemd/system/下,然后:
systemctl daemon-reload systemctl enable jmx_exporter_namenode systemctl start jmx_exporter_namenode这样exporter进程异常退出后,systemd会自动拉起来,监控链路本身的高可用才有保障。所有exporter配置和unit文件建议用Git管理,集群扩容的时候直接复制修改,省去重复劳动。
最后再分享一个我自己的习惯:每次搭完一套组件监控,我会把整套配置文件和Prometheus的采集配置一并备份到版本库里。下次再搭一套新集群,直接引用备份里的配置改个主机名就能用,不用再从零摸索。这个习惯已经帮我省下了无数次重复排查的时间。
本文还有配套的精品资源,点击获取