2018年第一次接触CDH集群时,那个凌晨三点被告警短信轰炸的夜晚至今记忆犹新。当时集群的NameNode堆内存溢出导致整个HDFS不可用,而我对着Cloudera Manager里密密麻麻的监控图表完全无从下手。五年间经历了从传统CDH到华为MRS的技术栈迁移,累计处理过327次P2级以上故障,最夸张的一个月收到了47张运维值班单。
大数据平台的运维就像在钢丝上跳舞——既要保证集群稳定性这个"基本生存需求",又要兼顾资源利用率、成本控制这些"高阶追求"。早期CDH时代我们主要靠CM的图形化界面救火,后来在MRS平台上逐渐形成了"监控埋点+自动化处置+根因分析"的三层防御体系。这个转变过程中积累的经验教训,值得每个大数据运维人仔细品味。
HDFS NameNode堆内存泄漏
2019年Q2连续三次出现NN fullGC导致集群不可用,最终发现是Hive metastore的批量分区操作触发了NN的FSDirectory内存暴涨。临时方案是调大-Xmx到32GB,长期方案是:
fs.trash.interval自动清理(建议1440分钟)batch.size从默认500降到200xml复制<property>
<name>dfs.namenode.handler.count</name>
<value>64</value> <!-- 建议为log(集群节点数)×20 -->
</property>
YARN资源死锁
某次业务方提交的Spark作业同时申请了200个vcore,而集群总资源只有180核,导致ResourceManager直接拒绝所有调度请求。我们现在严格执行:
capacity-scheduler.xml设置队列最大资源占比:xml复制<property>
<name>yarn.scheduler.capacity.root.production.maximum-capacity</name>
<value>80</value>
</property>
bash复制yarn scheduler –conf yarn-site.xml -modifyQueue \
-queue production -maxCapacity 80
Kafka磁盘爆满雪崩
日志集群曾因log.retention.hours设置过大导致磁盘使用率95%后,Kafka直接拒绝写入。现在我们的监控看板会重点跟踪:
/brokers/topics/[topic]/partitions/[partition]/log_sizeproperties复制log.retention.bytes=107374182400 # 100GB
log.retention.check.interval.ms=300000
2020年从CDH5.16升级到6.3.2时,因为忽略了一个隐藏配置dfs.client.failover.max.attempts,导致升级后HDFS客户端重试机制异常,业务方Spark作业大面积失败。现在我们的升级检查清单包含:
*.xml)重要提示:华为MRS的滚动升级虽然号称不影响业务,但实际测试发现HBase RegionServer在升级过程中会有约3秒的RPC延迟升高,需要业务侧做好重试机制。
V1.0 基础指标监控
采集jvm_heap_used、rpc_latency等基础指标,告警规则简单粗暴:
python复制if metric > threshold:
send_alert()
V2.0 业务语义监控
增加HDFS空间预测、YARN队列积压等业务指标,使用Prophet算法预测资源瓶颈:
python复制model = Prophet(interval_width=0.95)
model.fit(df[['ds','y']])
forecast = model.make_future_dataframe(periods=30)
V3.0 全链路追踪
通过OpenTelemetry实现从客户端到服务的全链路追踪,典型问题定位时间缩短60%:
go复制tracer := otel.Tracer("hdfs-client")
ctx, span := tracer.Start(ctx, "readBlock")
defer span.End()
V4.0 智能根因分析
基于历史故障库构建知识图谱,自动关联指标异常与配置变更:
sql复制MATCH (f:Fault)-[r:RELATED_TO]->(m:Metric)
WHERE m.name = 'nn_rpc_queue_length'
RETURN f.solution
配置管理即代码
所有集群配置版本化存储,变更通过Pull Request审核:
terraform复制resource "mrs_cluster" "prod" {
component_config {
hdfs {
dfs_replication = 3
io_file_buffer_size = 65536
}
}
}
故障自愈系统
典型故障处置流程自动化:
yaml复制- name: HDFS UnderReplicatedBlocks
condition: "hdfs_under_replicated_blocks > 1000"
actions:
- "hdfs dfsadmin -fetchImage"
- "systemctl restart namenode"
escalation: "page_oncall"
混沌工程演练
每月定期模拟NN宕机、磁盘损坏等场景:
bash复制chaosblade create network loss \
--percent 80 \
--interface eth0 \
--timeout 300
鉴权体系
MRS默认启用Ranger+Kerberos,而CDH常用Sentry。权限迁移时需要特别注意:
EXPORT/IMPORT PRIVILEGES转换hdfs dfs -getfacl备份存储分离架构
MRS支持OBS作为底层存储,但需要注意:
obs-distcp工具obs_request_latency监控接口差异
MRS的监控API路径与CDH不同:
bash复制# CDH风格
http://cm-host:7180/api/v19/clusters
# MRS风格
https://mrs-manager:28443/web/api/v2/clusters
某客户从CDH迁移到MRS后,Spark SQL性能下降约30%。通过以下调整实现20%的性能提升:
动态资源分配优化
修改spark.dynamicAllocation.maxExecutors与YARN队列最大资源匹配:
properties复制spark.dynamicAllocation.maxExecutors=200
spark.shuffle.service.enabled=true
OBS客户端缓存配置
针对OBS存储优化缓冲区:
xml复制<property>
<name>fs.obs.readahead.range</name>
<value>1MB</value>
</property>
本地化调度策略
启用数据本地化感知调度:
sql复制SET spark.locality.wait.node=10s;
SET spark.locality.wait.rack=20s;
JVM问题排查四件套
bash复制# 堆内存分析
jmap -histo:live <pid> | head -20
# GC日志解读
grep -A 5 "Full GC" gc.log
# 线程转储
jstack -l <pid> > thread_dump.txt
# 性能采样
async-profiler -d 60 -f profile.html <pid>
网络诊断技巧
mtr替代ping检测网络抖动tcpdump抓包时推荐过滤条件:bash复制tcpdump -i eth0 -w hdfs.pcap \
'port 8020 and tcp[13] & 8!=0'
我维护的运维知识库包含三个核心部分:
故障百科全书
按"现象-诊断-处置-预防"四段式记录,例如:
code复制## 现象
HBase RegionServer频繁挂起
## 诊断
jstack显示JVM停顿在GC
hbase.regionserver.handler.count=200过高
## 处置
逐步降低handler.count至50
增加-XX:+UseG1GC参数
## 预防
新集群部署时运行GC压力测试
配置变更追踪表
用Git版本控制+变更影响说明:
diff复制- <value>hdfs://namenode:8020</value>
+ <value>obs://bucket/path</value>
# 影响:所有MR作业需要更新输出路径
应急预案手册
明确不同级别故障的响应流程:
code复制P0级故障(全集群不可用):
1. 15分钟内召集应急小组
2. 每小时更新故障通报
3. 优先恢复服务后保留现场
真正有价值的运维经验往往来自那些凌晨三点的紧急处置。记得某次Kafka集群脑裂事故后,我们在ZooKeeper的/brokers/ids下发现了残留的临时节点,这个细节在任何文档中都没有提及。现在我的团队有个铁律:每个重大故障必须产出至少三条改进措施,这可能就是五年踩坑史带给我的最大财富——把每次痛苦都转化为防御体系的一块砖石。