我在执行Spark作业时遇到困难,大约一半的时间,它将选择在单个节点上处理所有数据,然后该节点的内存不足并死亡。
问题:如何确保这种情况不会一次发生?
该系统在Yarn上使用Spark 1.6.0,并从Hadoop 2.6数据存储中提取数据,所有代码均用Java编写。我在具有十二个节点(Amazon)的整个集群中动态分配资源。
DAG比较简单:
RDD --> mapToPair \
coGroup --> flatMapToPair --> reduceByKey --> save
RDD --> mapToPair /
Run Code Online (Sandbox Code Playgroud)
当它正确运行时,所有任务将在整个群集中得到很好的分配,整个工作大约需要20分钟。我们称其为“良好行为”。但是,有时候,flatMapToPair阶段实际上在单个执行程序中运行。我们称此为“不良行为”
当我为一个“不良行为”工作加载Spark UI并进入flatMapToPair阶段时,我发现实际上每个节点上运行着大约3-4个执行程序(与“不良行为”情况相同)。 。但是,除了一个完成之外,几乎所有其他操作都在不到一秒钟的时间内完成,其余的执行程序将运行10分钟,然后由于超出存储限制而被纱线杀死。
我已经尝试过的事情:
网络。搜索诸如“在一个节点上运行火花”之类的内容,几乎所有版本都会导致人们在Spark Shell或类似配置问题中以本地模式运行。鉴于我至少在某些时候表现良好,这些配置问题似乎不太可能(并且我检查了自己是否不是偶然地处于本地模式下,我有〜100个分区,...)。
在同一群集上运行的其他Spark作业表现良好。这似乎可以排除集群范围内的一些错误配置(哎呀,即使这项工作有时运行良好)。
群集利用率似乎并不会影响我是否表现良好。当群集被大量利用时,以及群集根本没有运行时,我都看到了这两种行为。
这似乎不是一个毛线问题,因为执行者都在整个集群中分布良好。我对此当然可以错了,但实际上问题似乎在于执行者之间的工作分配。
数据集中有多个键。我在coGroup和flatMapToPair之间插入了countByKey并打印了结果(用于20个左右的人口众多的键)。数据在这些最重要的键之间相当均匀地分布。
我为回应评论而尝试过的事情
在flatMapToPair调用之前对RDD重新分区,以强制进行500个分区。这只会将不良行为转移到重新分区阶段。
增加默认的并行性。我确实通过这种方式获得了更多分区,但是不良行为仍然停留在flatMapToPair阶段。
剥离数据(实际上,我在发布之前做了很多此类工作,但是未能将其包括在原始列表中)。我们只有10 GB的空间,而且我已经在加载所需的最小数据。
这是一个“有趣”的小heisenbug,其不良行为在添加调试日志后消失,然后在删除日志后消失,直到稍后再出现。我没有主意,因此,如果有人甚至建议了一些建议的诊断步骤,我将不知所措。
这是在将具有整数坐标的点按顺时针顺序排序的上下文中出现的问题,但这个问题与如何进行排序无关。
这个问题是关于二维向量具有自然循环排序的观察。具有通常溢出行为的无符号整数(或使用二进制补码的有符号整数)也具有自然循环排序。您能轻松地从第一个排序映射到第二个排序吗?
因此,确切的问题是是否存在从双补有符号 32 位整数对到无符号(或双补有符号)64 位整数的映射,使得任何按顺时针顺序排列的向量列表都映射到整数是否按递减(模溢出)顺序排列?
人们可能会询问的一些技术案例:
显而易见的答案是,因为只有大约 0.6*2^64 个不同的斜率,所以答案是肯定的,这样的地图存在,但我正在寻找一个易于计算的地图。我知道“轻松”是主观的,但我真的在寻找一些相当有效且实施起来并不可怕的东西。因此,特别是,不要计算光线和正 x 轴之间的每个格点(除非您知道一种聪明的方法来做到这一点而不将它们全部列举出来)。
需要注意的重要一点是,它可以通过映射到 6 个5位整数来完成。只需将向量投影到它碰到由x,y=+/-2^62限定的框的位置,然后向负无穷大舍入。您需要 63 位来表示该整数,另外需要 2 位来对您击中框的哪一侧进行编码。该实现需要稍微注意以确保您不会溢出,但只有一个分支和两个除法,否则非常便宜。如果您投影到 2^61,则它不起作用,因为您没有足够的分辨率来分离某些斜率。
另外,在您建议“只使用 atan2”之前,请计算atan2(1073741821,2147483643)并atan2(1073741820,2147483641)
编辑:扩展“atan2”评论:
给定两个互质且小于 2^31 的值 x_1 和 x_2(我在示例中使用了 2^31-5 和 2^31-7),我们可以使用扩展的欧几里德算法来找到 y_1 和 y_2,使得 y_1 /x_1-y_2/x_2 = 1/(x_1*x_2) ~= 2^-62。由于 arctan 的导数以 1 为界,atan2 的输出在这些值上的差异不会比这更大。所以,有很多向量对不能被 atan2 区分,因为 vanilla IEEE 754 双倍。
如果您有 80 位扩展寄存器,并且您确定可以在整个计算过程中在这些寄存器中保持驻留(并且不会被上下文切换踢出或只是简单地用完扩展寄存器),那么您没问题。但是,我真的不喜欢依赖驻留在扩展寄存器中的代码的正确性。