我相信每一个集群管理员,在长期管理多个不同体量及应用场景的集群后,都会多少产生情绪。其实这在我看来,是一个很微妙的事,即大家也已经开始人性化的看待每一个集群了。
既然是人性化的管理集群,我总是会思考几个方向的问题:
集群的特别之处在哪儿?
集群经常生什么病?
对于集群产生的突发疾病如何精准地做到靶向定位?
应急处理故障之后如何避免旧除新添?
在长期大规模集群治理实践过程中,也针对各个集群的各种疑难杂症形成了自己的西药(trouble shooting)丶中药(Returning for analysis)丶健身预防(On a regular basis to optimize)的手段及产品。
下面通过自我的三个灵魂拷问来分享一下自己对于大规模集群治理的经验及总结。
灵魂拷问1
集群量大,到底有啥特点?
集群数量多,规模大:管理着大小将近20个集群,最大的xxx集群和xx集群达到1000+节点的规模。
灵魂拷问2
平时集群容易生什么病,都有哪些隐患呢?
集群在整体功能性,稳定性,资源的使用等大的方面都会有一些痛点问题。
常见的文件数过多丶小文件过多丶RPC队列深度过高,到各个组件的版本bug,使用组件时发生严重生产故障,以及资源浪费等都是集群治理的常见问题。
灵魂拷问3
对于集群的突发疾病如何精准地解决故障?
对于集群突发的故障,平台应具备全面及时的监控告警,做到分钟级发现告警故障,推送告警通知,这是快速解决故障的前提保障。
下面将针对上面的9个集群问题或故障逐一解答如何解决。
1、底层计算引擎老旧,业务加工占用大量资源且异常缓慢。
集群底层使用MR计算引擎,大量任务未进合理优化,大多数任务占用上千core,上百TB内存,且对集群造成了大量的IO读写压力。
解决手段:通过监控“拎大头”,找出消耗资源巨大的任务,通过业务,计算引擎,参数调优来优化集群资源使用,提高集群算力。
业务优化:从业务角度明确来源数据,减少加载数据量。
计算引擎优化 :MR转Spark。
参数调优:小文件合并优化,内存内核调优,并发量调优,防止数据倾斜。
2、xx集群RPC故障问题。
现象概述:XX产线集群提交作业执行慢; 业务数据加工逻辑为读取HDFS新增文件>>>入库HBase; 遍历列表文件周期为5s。
根因分析:
解决方案:
阅读RPC源码:动态代理机制+NIO通信模型。
调整NN RPC关键参数,做对比实验。
1)优化系统参数配置:
ipc.server.handler.queue.size;
dfs.namenode.service.handler.count
2)将HDFS千万级目录扫描周期从5s调整为5分钟
3)增加集群RPC请求分时段分业务模型深度监控
3、xx集群由于承载对外多租户,面对各个租户提出的集群生产环境的需求都不一致,造成集群环境复杂化,yarn资源打满,并且容易出现负载过高的接口机,加重运维成本。
解决手段:
集群环境多版本及异构管理:
配置多版本Python环境,并搭建私有第三方库。
配置多版本Spark,Kafka环境。
实时监控yarn队列资源使用,监控yarn应用任务,重点优化。
配置明细接口机监控,优化接口机负载。
接口机从基础指标,top分析,CPU内存消耗过大的进程多维度监控,及时的合理调整优化接口机的调度任务,降低接口机负载。
4、xxx集群由于文件数过多,导致集群运行缓慢,NameNode进程掉线。
集群的文件对象达到九千多万。且集群的读写IO是写多读少。NameNode启动需要加载大量的块信息,启动耗时过长。
解决手段:
计算引擎优化 :尽量使用Spark,有效率使用内存资源,减少磁盘IO读写。
周期性清理:根据HDFS业务目录存储增量,定期协调业务人员清理相关无用业务数据。
块大小管理:小文件做合并,增加block大小为1GB,减少小文件块数量。
深度清理:采集监控auit日志做HDFS文件系统的多维画像。深入清理无用数据表,空文件,废文件。
5、HDFS数据目录权限管理混乱,经常造成数据误删或丢失。
由于下放的权限没有及时回收,或者一些误操作造成了数据的误删和丢失。
解决办法:
业务划分:明确梳理各个业务对应权限用户,整改当前HDFS数据目录结构,生产测试库分离控制。
数据生命周期管理:
6、yarnJOB造成节点负载过高影响了其他job运行。
某些节点CPU负载很高影响了job任务的运行,发现有些节点的负载从9:30到现在一直很高,导致job任务执行了大概7个小时。
解决办法:
找到耗时task执行的节点,确实发现负载很高,并找到了此任务对应的进程。
查看此进程的堆栈信息,发现Full GC次数很多,时长很长大概6个小时,频繁的Full GC会使CPU使用率过高。
查看job进程详情发现,java heap内存只有820M,task处理的记录数为7400多万,造成堆内存不足频繁出发Full GC。
推荐下次执行任务时设置如下参数大小:
hive> set mapreduce.map.memory.mb=4096;
hive> set mapreduce.map.java.opts=-Xmx3686m;
7、NameNode切换后部分Hive表无法查询。
小集群NameNode发生切换,并出现Hive某库下的表和其有关联的表无法使用的情况报错如下:
截图报错,表明当前NameNode节点为stanby节点。经过排查发现,Hive的Metadata中有些partition列的属性还保留之前配置的NameNode location。
解决办法:
备份Hive所在的MySQL元数据库 # mysqldump -uRoot -pPassword hive > hivedump.sql;
进入Hive所在的MySQL数据库执行,修改Hive库下SDS表下的location信息,涉及条数9739行。把指定IP的location替换成nameservice ;
UPDATE SDS SET LOCATION = REPLACE(LOCATION, 'hdfs://ip:8020', 'hdfs://nameservice1') where LOCATION like 'hdfs://ip%';
切换NameNode验证所影响Hive表是否可用;
业务全方面验证 ;
变更影响范围:本次变更可以在线进行实施,避开业务繁忙段,对业务无影响;
回退方案:从备份的mysqldump文件中恢复mysql hive元数据库 mysql -uUsername -pPassword hive < hivedump.sq。
8、Spark任务运行缓慢,且经常执行报错。
产线集群提交作业执行报错,个别Task执行耗时超过2h: ERROR server.TransportChannelHandler: Connection to ip:4376 has been quiet for 120000 ms while there are outstanding requests. Assuming connection is dead; please adjust spark.network.timeout if this is wrong.
根因分析:
报错表象为shuffle阶段拉取数据操作连接超时。默认超时时间为120s。
深入了解Spark源码:在shuffle阶段会有read 和 write操作。
首先根据shuffle可使用内存对每一个task进行chcksum,校验task处理数据量是否超出shuffle buffer 内存上限。该过程并不是做全量chcksum,而是采用抽样的方式进行校验。
其原理是抽取task TID ,与shuffle内存校验,小于shuffle内存上限,则该区间的task都会获取 task data 遍历器进行数据遍历load本地,即HDFS Spark中间过程目录。
这样会导致一些数据量过大的task成为漏网之鱼,正常来说,数据量过大,如果被校验器采样到,会直接报OOM,实际情况是大数据量task没有被检测到,超出buffer过多,导致load时,一部分数据在内存中获取不到,进而导致连接超时的报错假象。
解决方案:
1)调优参数配置:
spark.shuffle.manager(sort),spark.shuffle.consolidateFiles (true),spark.network.timeout(600s)。报错解决,运行耗时缩短一小时。
2)excutor分配内存从16g降为6g。内存占用节省三分之二,运行耗时增加一小时。
9、某HBase集群无法PUT入库问题处理。
集群情况介绍:HDFS总存储 20+PB,已使用 75+%,共 600+ 个 DN 节点,大部分数据为 2 副本(该集群经历过 多次扩容,扩容前由于存储紧张被迫降副本为 2),数据分布基本均衡。集群上只承载了HBase数据库。
故障描述:因集群部分 DN 节点存储使用率非常高(超过 95%),所以采取了下线主机然后再恢复 集群中这种办法来减轻某些 DN 存储压力。
且集群大部分数据为 2 副本,所以在这个过程 中出现了丢块现象。通过 fsck 看到已经彻底 miss,副本数为 0。
因此,在重启 HBase 过程中,部分 region 因 为 block 的丢失而无法打开,形成了 RIT。
对此问题,我们通过 hadoop fsck –delete 命令清除了 miss 的 block。然后逐库通过 hbase hbck –repair 命令来修复 hbase 在修复某个库的时候在尝试连接 ZK 环节长时间卡死(10 分钟没有任何输出),被迫只能 中断命令。
然后发现故障表只有 999 个 region,并且出现 RIT,手动 assign 无效后,尝试了重启库及再次 repair 修 复,均无效。
目前在 HDFS 上查看该表 region 目录总数为 1002 个,而 Hbase UI 上是 999 个,正常值为 1000 个。
问题处理:后续检查发现在整个集群的每张 HBase 表都有 region un-assignment 及 rowkey 存在 hole 问题(不是单张表存在问题)。
运行 hbase hbck -details -checkCorruptHFiles 做集群状态检查,检查结果如下:
… ERROR: Region { meta => index_natip201712,#\xA0,1512009553152.00d96f6b2de55b56453e7060328b7930., hdfs => hdfs://ns1/hbase_ipsource3/data/default/index_natip201712/00d96f6b2de55b56453e7060328b7930, deployed => } not deployed on any region server. ERROR: Region { meta => index_natip201711,Y`,1509436894266.00e2784a250af945c66fb70370344f2f., hdfs => hdfs://ns1/hbase_ipsource3/data/default/index_natip201711/00e2784a250af945c66fb70370344f2f, deployed => } not deployed on any region server. … ERROR: There is a hole in the region chain between \x02 and \x02@. You need to create a new .regioninfo and region dir in hdfs to plug the hole. ERROR: There is a hole in the region chain between \x04 and \x04@. You need to create a new .regioninfo and region dir in hdfs to plug the hole.
每张表可用(online)的 region 数都少于 1000,共存在 391 个 inconsistency,整个集群基本不可用。
因为每张表都不可用,所以通过新建表并将原表的 HFile 文件 BulkLoad 入新表的方案基本不可行。
第一、这种方案耗时太长;第二、做过一个基本测试,如果按照原表预 分区的方式新建表,在 BulkLoad 操作后,无法在新表上查询数据(get 及 scan 操作均 阻塞,原因未知,初步估计和预分区方式有关)。
基于以上分析,决定采用 hbck 直接修复原表的方案进行,不再采用 BulkLoad 方案。
运行命令 hbae hbck -repair -fixAssignments -fixMeta,报Repair 过程阻塞异常。
查 HMaster 后台日志,发现是某个 RegionServer(DSJ-signal-4T-147/10.162.0.175)的连接数超多造成连接超时。重启该 RegionServer 后再次运行 hbck -repair -fixAssignments -fixMeta 顺序结束,并成功修复了所有表的 region un-assignment、hole 及 HBase:meta 问题。
应用层测试整个集群入库正常,问题处理完成。
10、Kafka集群频频到达性能瓶颈,造成上下游数据传输积压。
Kafka集群节点数50+,集群使用普通SATA盘,存储能力2000TB,千亿级日流量,经常会出现个别磁盘IO打满,导致生产断传,消费延迟,继而引发消费offset越界,单个节点topic配置记录过期等问题。
1)降低topic副本:
建议如果能降低大部分topic的副本,这个方法是简单有效的。
降副本之后再把集群的拷贝副本所用的cpu核数降低,可以由num.replica.fetchers=6降低为num.replica.fetchers=3。磁盘IO使用的num.io.threads=14升为num.io.threads=16。num.network.threads=8升为num.network.threads=9。此参数只是暂时压榨机器性能,当数据量递增时仍会发生故障。
2)设定topic创建规则,针对磁盘性能瓶颈做分区指定磁盘迁移:
如果降低副本收效甚微,考虑到目前集群瓶颈主要在个别磁盘读写IO达到峰值,是因磁盘的topic分区分配不合理导致,建议首先做好针对topic分区级别IO速率的监控,然后形成规范合理的topic创建分区规则(数据量,流量大的topic先创建;分区数*副本数是磁盘总数的整数倍),先做到磁盘存储的均衡,再挑出来个别读写IO到达瓶颈的磁盘,根据监控找出读写异常大分区。
找出分区后再次进行针对topic的分区扩容或者针对问题分区进行指定磁盘的迁移。这样集群的整体利用率和稳定性能得到一定的提升,能节省集群资源。
3)Kafka版本升级及cm纳管:
将手工集群迁移至cm纳管,并在线升级Kafka版本。
4)zk和broker节点分离:
进行zk和broker节点的分离工作,建议进行zk节点变化而不是broker节点变化,以此避免数据拷贝带来的集群负荷,建议创建测试topic,由客户端适当增加批大小和减少提交频率进行测试,使集群性能达到最优。