因特殊原因公司服务器从晚上6点开始CPU资源使用率飙升至100%
然后运维重启服务器,重新构建此服务器上所有作业
然而第二天早上查看日志发现,有一个job作业启动失败,经过一系列排查最终解决,特此记录一下
此作业是sparkStreaming 读取kafka topic并存储至hbase ,offset保存在zookeeper;
此问题并非是常见的offset过期或offset不一致问题; 请往下看
为了避免是代码问题,首先在自己搭建的测试环境中运行没有问题
后放到生产环境中直接报错
报错内容 :
Job aborted due to stage failure: Aborting TaskSet 0.0 because task 5 (partition 5) cannot run anywhere due to node and executor blacklist. Blacklisting behavior can be configured via spark.blacklist.*.
翻译:
*由于阶段失败而中止的作业:由于节点和执行者黑名单,任务5(分区5)无法在任何地方运行,正在中止任务集。黑名单行为可以通过spark.blacklist.配置。
错误显示任务5无法在任何地方运行,所以终止所有任务,后面还跟了一个黑名单配置
后上 谷歌查询,有一篇文章详细解释了spark黑名单机制,链接如下:
[https://www.jianshu.com/p/8af15cb644ef]
文章内容简单来讲就是:
• 有个节点上的磁盘由于某些原因出现间歇性故障,导致某些扇区不能被读取。假设我们的 Spark 作业需要的数据正好就在这些扇区上,这将会导致这个 Task 失败。
• 这个作业的 Driver 获取到这个信息,知道 Task 失败了,所以它会重新提交这个 Task。
• Scheduler 获取这个请求之后,它会考虑到数据的本地性问题,所以很可能还是把这个 Task 分发到上述的机器,因为它并不知道上述机器的磁盘出现了问题。
因为这个机器的磁盘出现问题,所以这个 Task 可能一样失败。然后 Driver 重新这些操作,最终导致了 Spark 作业出现失败
于是开始怀疑是机器故障或者kafka分区损坏等可能,但经过排查发现kafka分区正常:
服务器集群运行亦正常,况且公司使用的CDH 5.14版本,对应的spark是1.6版本,根本没有黑名单配置项,黑名单spark.blacklist.配置是在spark2.2.0版本后才有的功能
随排除了kafka及硬件问题的可能
后来想到spark提交作业的时候给了一个选项:
–spark.dynamicAllocation.enabled=true
指定是动态资源调配
为了方便调错于是去掉其他配置,直接改成最接地气的启动方式:
spark-submit --class com.shenque.start.KafkaZKManager --master yarn-client --executor-memory 1000M
–executor-cores 2 --num-executors 3 --driver-memory 1000M jar包名称
启动后 依然报错,但是错误却变了:
Container marked as failed: container_e18_1582561040524_1837_01_000002 on host: Exit status: 143. Diagnostics: Container killed on request. Exit code is 143
Container exited with a non-zero exit code 143
Killed by external signal
翻译:
标记为失败的容器:Container_e18_1582561040524_1837_01_000002on退出状态:143。诊断:应请求终止容器。出口代码是143
容器以非零退出代码143退出
被外部信号杀死
再次谷歌,于是找到下面这篇文章:
https://blog.csdn.net/yijichangkong/article/details/51332432
此文章虽然和我报错的内容不太一样,但是文中一句话提醒了我:
从hive报错看是由于物理内存达到限制,导致container被kill掉报错。
突然想到,从昨天下午6点到今天上午8点十多个小时,kafka有可能积压了大量数据,内存空间不足导致任务失败
于是增大内存,将executor-memory设置为4G,将启动脚本改为:
spark-submit --class com.shenque.start.KafkaZKManager --master yarn-client --executor-memory 4000M
–executor-cores 2 --num-executors 6 --driver-memory 2000M jar包名称
为了探究问题所在,于是开始一条一条看日志,抽丝剥茧发现了一句话:
cluster.YarnClientSchedulerBackend: Disabling executor 1.
翻译:
cluster.YarnClientSchedulerBackend:禁用执行器1。
一言以蔽之:Yarn把执行器给禁用了
继续往下翻发现,发现所有的executor执行器都被禁用了:
那干脆就不用yarn来做资源管理,直接用spark-sumit local[6] 本地来执行程序
更改作业脚本:
spark-submit --class com.shenque.start.KafkaZKManager --master local[6] --executor-memory 4000M
–executor-cores 2 --num-executors 6 --driver-memory 2000M jar包名称
但你不可能让程序一直运行在本地上,于是等了一会kill掉程序,再次部署到yarn上执行:
于是明白了问题所在,在本地运行的时候spark将kafka上积压的数据全部消费掉了
而此时再运行yarn上的时候不需要太大内存就可以成功
那么我们之前调大了内存为何运行还是失败呢,经过一番查找资料发现,很有可能是公司的服务器中限制了Yarn的最大Container大小!
在hadoop2及以上版本中,task 是运行在container中的。
Yarn配置文件中会限制Container的最小内存(yarn.scheduler.minimum-allocation-mb)、最大内存(yarn.scheduler.maximum-allocation-mb)。
如果container的内存超限,会被yarn杀死。
所以之所以Yarn会杀死6个executor,很有可能是超过了设置的container内存阈值导致的
后来经过本地无yarn模式将积压数据消费后,再用不超过container阈值的内存容量在Yarn上运行即会成功;
至此问题解决,特此记录