Spark超时问题一例(Connection has been quiet)

这是用Spark Mllib ALS算法做离线推荐时遇到的问题。我们对历史日志作统计和评分,然后用ALS来训练模型,最后为每个用户做个性化的产品推荐。

现象是,driver在完成推荐之后,调用foreach输出推荐结果。从Spark UI看到,foreach这一步迟迟不执行。

大约300秒之后(我们的spark.network.timeout是300秒),各个executor报告超时:

Connection to xxx/x.x.x.x:30285 has been quiet for 300000 ms while there are outstanding requests. Assuming connection is dead; please adjust spark.network.timeout if this is wrong
随后各executor被重启再次执行。若再次执行失败,则达到每个executor最多失败2次的默认配置,认定应用执行失败,并关闭Spark UI端口。此时Spark UI就访问不了,但通过yarn application -list命令却能看到应用仍在执行。

我们做了各种尝试,发现:
1、修改内存和CPU参数,几乎没有影响。
2、只读取20天的日志,基本不出问题;25天日志有一定概率失败;30天以上失败概率非常高。

其实30天的日志量,也不是特别大,对于分布式应用来说根本没有压力;比如对同样的日志,通过Hive SQL执行各种复杂的查询,也没有遇到问题;应该是使用推荐算法才出现的特殊情况。
因为日志的天数能够决定执行成功率,于是我们加了些打印,再次分别尝试20天、25天、30天的日志量。得到这些数据:

20天日志的分区数
rating分区数 558
recommendRDD分区数 77841

25天日志的分区数:
rating分区数 753
recommendRDD分区数 141376

30天日志的分区数:
rating分区数 889
recommendRDD分区数 197136

(注:recommendRDD是rating通过计算得来的)

很明显,随着天数的增加,推荐结果recommendRDD分区数增加的特别多。同时我们发现30天的情况下,driver的日志中有这么一行:

16/10/08 18:43:19 INFO cluster.YarnClusterScheduler: Adding task set 235.0 with 197136 tasks

之后大约5分钟没有任何日志,直到executor超时:

16/10/08 18:48:25 INFO yarn.YarnAllocator: Completed container container_1469065165073_3636_01_000004 on host: CDM1C02-209018034.wdds.com (state: COMPLETE, exit status: 1)
16/10/08 18:48:25 WARN yarn.YarnAllocator: Container marked as failed: container_1469065165073_3636_01_000004 on host: CDM1C02-209018034.wdds.com. Exit status: 1. Diagnostics:

这个197136 tasks正好等于分区数。会不会是因为任务数、分区数太多,而一直在Adding中?如果是,那么我们肯定能够看到调用栈一直在执行某段代码。

于是我们下载对应版本的Spark源码,搜索Adding task set,找到这么一个函数:createTaskSetManager。

然后复现问题,在foreach再次卡住的时候,也就是日志显示Adding task set 235.0 with 197136 tasks的时候,在Spark UI的driver的Thread dump页面一搜,果然搜到这么一个调用栈:

Spark超时问题一例(Connection has been quiet)_第1张图片

反复刷新页面,确实这个调用栈一直不变。那就肯定了直接原因是: 任务数太多

那么怎么减少任务数呢?当然就是减少分区数。我们这种情况,直接对recommendRDD做repartition还不行,仍然会卡住;必须对rating做repartition,减少rating的分区数之后,recommendRDD分区数也相应减少了。比如rating.repartition(550),得出的recommendRDD的分区数只有75625,远小于197136,Adding task set就不再卡住了。


你可能感兴趣的:(Spark超时问题一例(Connection has been quiet))