重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
耗时很长时间解决了一个spark in docker的问题,记录一下。
成都创新互联IDC提供业务:联通机房服务器托管,成都服务器租用,联通机房服务器托管,重庆服务器租用等四川省内主机托管与主机租用业务;数据中心含:双线机房,BGP机房,电信机房,移动机房,联通机房。
这是个非常奇怪的问题,找遍谷歌都找不到答案,与其说是分析出来倒不如说是偶然发现。
先介绍一下架构和环境。
Z机器是docker的宿主机,在每个docker里面都跑了一个Zeppelin用作数据分析,之所以这样弄,是客户要求每个人的环境都必须是独立的。
Zdocker假设是Z上面跑着zeppelin的运行的一个docker镜像。
Zdocker使用默认的bridge方式连接到外部集群
Hadoop集群按照加入集群的先后顺序分为两部分进行观察。A为先加入集群的机器有31台,B为后加入集群的机器15台。
Spark使用client方式提交,用YARN做资源管理。
表象:
Zdocker里面通过Zeppelin页面提交的Spark计算任务一直都是正常的,直到B的15台加入到集群里
B的15台配置从操作系统到网络到JVM到hadoop全部一模一样,没有区别。
B加入后,所有从Zdocker里面提交的Spark任务全部不能跑,executor在15台机器执行时会报 NoRouteToHost gateway: 7337
B加入后,所有在Zdocker外面提交的Spark任务全部正常。
B加入后,所有executor不运行在B机器上的全部正常
B加入后,Zdocker内外所有MapReduce任务正常。
在YARN里去掉B的15台机器,一切正常。
分析:
7337为spark的yarn shuffle端口
第一阶段
既然是NoRouteToHost,第一反应是DNS问题,检查所有DNS和hosts文件,没有发现问题,检查iptables,route表,全部无问题,解决失败。
第二阶段
怀疑是spark bug,我想知道 gateway 是从哪冒出来的,翻阅了spark里面报错相关的scala和java代码,没有找到这个跟gateway相关的东西。
第三阶段
因为B加入前是正常的,B加入后就不正常了,检查docker里面的DNS和hosts,全部正常,继续失败。
第四阶段
怀疑环境变量不同,检查所有A,B机器配置,环境变量完全一样。
因为是yarn shuffle,怀疑spark-assembly问题,检查后发现无问题。
第五阶段
尝试暴力解决,将gateway加入DNS解析,强行指到B集群的一台机器上。也就是所有的spark 外部shuffle会指向到一台机器的 7337端口。好,跑了一天没问题,第二天就有问题了,那台被强行指定的机器报找不到作业在本地shuffle的index文件。
第六阶段
尝试在docker里面发现问题,看了一下docker的路由表,发现172.17.42.1是docker的网关,抱着死马心态在docker里面ping了一下gateway主机名,发现通的。于是裆下一紧,感觉有门可入。
docker内部默认的网关是172.17.42.1,然后默认还给了个hostname叫gateway,或许这就是了。
于是跑到A找了一台机器ping gateway主机名,ping卡死,因为无论DNS还是hosts,在任何hadoop的节点都是没有解析过gateway这个主机名的。然后到B找了一台机器ping,直接退出报 ping: unknown host gateway。
于是开始琢磨,两个机器网络环境不同,或许这就是问题点了。
A的几十台机器,因为安全需要,没有开放任何外网访问。所以在A的机器上ping gateway时,根本连域名都解析不了,所以会卡死。而B的十几台机器因为是新加的,运维忘了关闭外网访问,所以能找到公网的域名解析服务器,但是公网解析不了gateway域名,于是直接返回 unknown host 并退出。
让运维关闭B机器的公网访问,再从Zdocker上面提交作业,一切正常。
原因:
解决了问题再回来分析一下应该是因为zeppelin从docker里面提交spark作业,spark是client方式跑,driver是跑在docker里面的,driver在向docker外的yarn申请资源分配executor的时候,在哪里带上了gateway这个主机名作为环境变量传递给了executor的container。如果没有外网访问,executor会使用本机的 7337作为yarn shuffle的端口,而有了外网访问,executor会去查询gateway的ip,但是DNS返回错误,于是就会造成executor执行错误。这也很好的解释了为什么docker外面的spark作业无论B是否启动都不会报错正常执行。
所以这他妈其实是一个很低端的错误,只是谁都不会想到,spark执行的失败还能跟是否访问公网有关。就跟上次解决MR速度慢一样,谁能想到网卡能他妈自己跳成10Mbps啊。
后续还需要继续研究docker的网络机制和spark的driver和executor之间的传参机制,才能彻底干掉这个问题。