Bug剖析篇-"Facebook 60TB+级的Apache Spark应用案例"

简介: Facebook 60TB+级的Apache Spark应用案例 里大体有两方面的PR,一个是Bug Fix,一个是性能优化。这篇文章会对所有提及的Bug Issue进行一次解释和说明。也请期待下一篇。

前言

Facebook 60TB+级的Apache Spark应用案例,本来上周就准备看的,而且要求自己不能手机看,要在电脑上细细的看。然而终究是各种忙拖到了昨天晚上。 
文章体现的工作,我觉得更像是一次挑战赛,Facebook团队通过层层加码,最终将单个Spark Batch实例跑到了60T+ 的数据,这是一个了不起的成就,最最重要的是,他们完成这项挑战赛后给社区带来了三个好处:
  1. 在如此规模下,发现了一些Spark团队以前很难发现的Bug
  2. 提交了大量的bug fix 和 new features,而且我们可以在Spark 1.6.2 /Spark 2.0 里享受到其中的成果
  3. 在如此规模下,我们也知道我们最可能遇到的一些问题。大体是OOM和Driver的限制。
说实在的,我觉得这篇文章,可以算是一篇工程论文了。而且只用了三个人力,不知道一共花了多久。
值得注意的是,大部分Bug都是和OOM相关的,这也是Spark的一个痛点,所以这次提交的PR质量非常高。

Bug 剖析

Make PipedRDD robust to fetch failure  SPARK-13793

这个Issue 还是比较明显的。PipedRDD 在Task内部启动一个新的Java进程(假设我们叫做ChildProcessor)获取数据。这里就会涉及到三个点:
  1. 启动一个线程往 ChildProcessor 写数据 (stdin writer)
  2. 启动一个线程监控ChildProcessor的错误输出 (stderr reader)
  3. 获取ChildProcessor输入流,返回一个迭代器(Iterator)
既然都是读取数据流,如果数据流因为某种异常原因关闭,那必然会抛出错误。所以我们需要记录这个异常,对于1,2 两个我们只要catch住异常,然后将异常记录下来方便后续重新抛出。 那么什么时候抛出呢?迭代器有经典的hasNext/next方法,每次hasNext时,我们都检查下是否有Exception(来自1,2的),如果有就抛出了。既然已经异常了,我们就应该不需要继续读取这个分区的数据了。否则数据集很大的情况下,还要运行很长时间才能运行完。
在hasNext 为false的情况下,有两类情况,一类是真的没有数据了,一类是有异常了,比如有节点挂了,所以需要检测下ChildProcessor的exitStatus状态。如果不正常,就直接抛出异常,进行重试。
对于1,2两点,原来都是没有的,是这次Facebook团队加上去的。

Configurable max number of fetch failures SPARK-13369

截止到我这篇文章发出,这个Issue 并没有被接收。
我们知道,Shuffle 发生时,一般会发生有两个Stage 产生,一个ShuffleMapStage (我们取名为 MapStage),他会写入数据到文件中,接着下一个Stage (我们取名为ReduceStage) 就会去读取对应的数据。 很多情况下,ReduceStage 去读取数据MapStage 的数据会失败,可能的原因比如有节点重启导致MapStage产生的数据有丢失,此外还有GC超时等。这个时候Spark 就会重跑这两个Stage,如果连续四次都发生这个问题,那么就会将整个Job给标记为失败。 现阶段(包括在刚发布的2.0),这个数值是固定的,并不能够设置。
@markhamstra 给出的质疑是,如果发生节点失败导致Stage 重新被Resubmit ,Resubmit后理论上不会再尝试原来失败的节点,如果连续四次都无法找到正常的阶段运行这些任务,那么应该是有Bug,简单增加重试次数虽然也有意义,但是治标不治本。
我个人认为在集群规模较大,任务较重的过程中,出现一个或者一批Node 挂掉啥的是很正常的,如果仅仅是因为某个Shuffle 导致整个Job失败,对于那种大而耗时的任务显然是不能接受的。个人认为应该讲这个决定权交给用户,也就是允许用户配置尝试次数。

Unresponsive driver SPARK-13279

这个Bug已经在1.6.1, 2.0.0 中修复。 这个场景比较特殊,因为Facebook产生了高达200k的task数,原来给pendingTasksForExecutor:HashMap[String, ArrayBuffer[Int]]  添加新的task 的时候,都会根据Executor名获取到已经存在的列表,然后判断该列表是否已经包含了新Task,这个操作的时间复杂度是O(N^2)。在Task数比较小的情况下没啥问题,但是一旦task数达到了200k,基本就要五分钟,给人的感觉就是Driver没啥反应了。
而且在实际运行任务的过程中,会通过一个特殊的dequeueTaskFromList结构来排除掉已经运行的任务,所以我们其实在addPendingTask 过程中不需要做这个检测。
074fe9cefa076c167c9b1f711152a51404485ad6
因为证明了没有副作用,所以现在是没啥问题了。但是我个人认为其实还有一种办法是,取一个阈值,如果小于某个阈值则做double duplicate check,否则就直接加进去就好了。Spark 在很多地方也是这么做的。
这里对于那些Task数特别大的朋友有福了。

TimSort issue due to integer overflow for large buffer 

该Bug在1.6.2, 2.0.0 已经被解决。这个bug引起的问题现象初看起来会比较让人费解,大体如下:
9190cb6d6353234bf6969eb614fa1d03fbbea44e
Snip20160906_21.png
如图所示似乎违反了签名。其实问题本身确实比较复杂,通过提交了两个patch 才解决了该问题。
一开始Facebook的哥们觉得应该是排序过程中内存的数据(比如ShuffleExternalSorter等Sorter) 超过8G 引起的,所以限制了数量,大于一定数量之后就进行spill操作。 后面一个新的PR应该是发现了问题的根源,在UnsafeSortDataFormat.copyRange() 和ShuffleSortDataFormat copyRange() 里,里面数组的偏移量是Integer类型,虽然数据集的大小不至于超过Int的最大值,但是在特定数据分布下且数据集>268.43 million 并则会触发这个Bug。我看了下,原先 Platform.copyMemory 签名本身也是Long的,但是实现copyRange的时候,默认传进去的是Int,所以产生了这个问题。大家瞅一眼代码就知道了。
49f4f40028696e003e51f968970d9388110b56c9
Snip20160906_23.png

Fix Spark executor OOM 

该Bug 也是在1.6.2, 2.0.0 被修正。
这个问题是这样的,Spark MemoryManager 可能认为还有10M内存,但是此时实际JVM可以提供给MemroyManager的内存只有5M了。所以分配内存的时候,就抛OOM了。这个时候应该捕获该OOM,并且保留已经申请到内存不归还,让MemoryManger 以为内存不够了,然后进行splill操作,从而凑足需要的内存。我们看TaskMemoryManager.allocatePage 方法。
22c0d91e5191d388c2af4a6035dfc494c7da055e
Snip20160906_25.png
如果发生OOM了,则会捕获一次,,并且通过acquiredButNotUsed记住已经申请的量,最后再次调用allocatePage。这个时候allocatePage里的acquireExecutionMemory 方法可能发现自己内存不足了,就会发生spill了,从而释放出内存。
其实这之前的代码也考虑过,但是没有在allocatePage的层次上做。这个Bug估计在单个Executor 并行运行Task数比较多的时候比较严重和容易发生的。

Fix memory leak in the sorter SPARK-14363

这个Bug 也是在1.6.2, 2.0.0被修正。
在Spark排序中,指针和数据时分开存储的,进行spill操作其实是把数据替换到磁盘上。但是指针数组是必须在内存里。当数据被spill后,相应的,指向这些记录的指针其实也是要被释放的。数据量很大的时候,指针数组的大小也很可观。而且有一点值得指出的是,比如某个Executor 有五个Task并行运行,如果其中有三个完成了,那么可用内存增大,缓存到内存的数据就会变多,这个时候剩下的两个Task的指针数组也会增大,从而占用更多内存,接着新运行的三个Task可用内存变小了,从而失去了公平性。
这些各个Sorter里都需要修正。
074fe9cefa076c167c9b1f711152a51404485ad6
Snip20160906_26.png

红框部分便是释放指针数组的地方。里面会重新按初始initialSize值申请一块指针数组的内存。
目录
相关文章
|
17天前
|
分布式计算 大数据 数据处理
Apache Spark的应用与优势:解锁大数据处理的无限潜能
【8月更文挑战第23天】Apache Spark以其卓越的性能、易用性、通用性、弹性与可扩展性以及丰富的生态系统,在大数据处理领域展现出了强大的竞争力和广泛的应用前景。随着大数据技术的不断发展和普及,Spark必将成为企业实现数字化转型和业务创新的重要工具。未来,我们有理由相信,Spark将继续引领大数据处理技术的发展潮流,为企业创造更大的价值。
|
2月前
|
存储 运维 关系型数据库
探索 Apache Paimon 在阿里智能引擎的应用场景
本文整理自Apache Yarn && Flink Contributor,阿里巴巴智能引擎事业部技术专家王伟骏(鸿历)老师在 5月16日 Streaming Lakehouse Meetup · Online 上的分享。
24976 33
探索 Apache Paimon 在阿里智能引擎的应用场景
|
2月前
|
存储 缓存 Apache
Apache Paimon 在蚂蚁的应用
本文整理自 Apache Paimon Committer 闵文俊老师在5月16日 Streaming Lakehouse Meetup · Online 上的分享。Apache Paimon 是一种实时数据湖格式,设计用于流批一体处理,支持实时更新和OLAP查询。它采用LSM Tree结构,提供多种Changelog Producer和Merge Engine,支持高效的数据合并。Paimon适用于流读、批读及时间旅行查询,与多种查询引擎兼容。在蚂蚁集团的应用中,Paimon降低了资源开销,提升了查询性能,简化了研发流程,特别是在去重、核对场景和离线查询加速方面表现突出。
440 7
Apache Paimon 在蚂蚁的应用
|
1月前
|
分布式计算 资源调度 测试技术
“Spark Streaming异常处理秘籍:揭秘如何驯服实时数据流的猛兽,守护你的应用稳如泰山,不容错过!”
【8月更文挑战第7天】Spark Streaming 是 Apache Spark 中的关键组件,用于实时数据流处理。部署时可能遭遇数据问题、资源限制或逻辑错误等异常。合理处理这些异常对于保持应用稳定性至关重要。基础在于理解其异常处理机制,通过 DSC 将数据流切分为 RDD。对于数据异常,可采用 try-catch 结构捕获并处理;资源层面异常需优化 Spark 配置,如调整内存分配;逻辑异常则需加强单元测试及集成测试。结合监控工具,可全面提升应用的健壮性和可靠性。
51 3
|
20天前
|
分布式计算 Hadoop 大数据
大数据处理框架在零售业的应用:Apache Hadoop与Apache Spark
【8月更文挑战第20天】Apache Hadoop和Apache Spark为处理海量零售户数据提供了强大的支持
32 0
|
2月前
|
分布式计算 大数据 Spark
Spark大数据处理:技术、应用与性能优化(全)PDF书籍推荐分享
《Spark大数据处理:技术、应用与性能优化》深入浅出介绍Spark核心,涵盖部署、实战与性能调优,适合初学者。作者基于微软和IBM经验,解析Spark工作机制,探讨BDAS生态,提供实践案例,助力快速掌握。书中亦讨论性能优化策略。[PDF下载链接](https://zhangfeidezhu.com/?p=347)。![Spark Web UI](https://img-blog.csdnimg.cn/direct/16aaadbb4e13410f8cb2727c3786cc9e.png#pic_center)
91 1
Spark大数据处理:技术、应用与性能优化(全)PDF书籍推荐分享
|
24天前
|
分布式计算 Serverless 数据处理
EMR Serverless Spark 实践教程 | 通过 Apache Airflow 使用 Livy Operator 提交任务
Apache Airflow 是一个强大的工作流程自动化和调度工具,它允许开发者编排、计划和监控数据管道的执行。EMR Serverless Spark 为处理大规模数据处理任务提供了一个无服务器计算环境。本文为您介绍如何通过 Apache Airflow 的 Livy Operator 实现自动化地向 EMR Serverless Spark 提交任务,以实现任务调度和执行的自动化,帮助您更有效地管理数据处理任务。
138 0
|
25天前
|
存储 Ubuntu 应用服务中间件
如何在 Ubuntu 14.04 上使用 Passenger 和 Apache 部署 Rails 应用
如何在 Ubuntu 14.04 上使用 Passenger 和 Apache 部署 Rails 应用
12 0
|
30天前
|
关系型数据库 Linux 网络安全
"Linux系统实战:从零开始部署Apache+PHP Web项目,轻松搭建您的在线应用"
【8月更文挑战第9天】Linux作为服务器操作系统,凭借其稳定性和安全性成为部署Web项目的优选平台。本文以Apache Web服务器和PHP项目为例,介绍部署流程。首先,通过包管理器安装Apache与PHP;接着创建项目目录,并上传项目文件至该目录;根据需要配置Apache虚拟主机;最后重启Apache服务并测试项目。确保防火墙允许HTTP流量,正确配置数据库连接,并定期更新系统以维持安全。随着项目复杂度提升,进一步学习高级配置将变得必要。
54 0
|
2月前
|
分布式计算 Hadoop Serverless
数据处理的艺术:EMR Serverless Spark实践及应用体验
阿里云EMR Serverless Spark是基于Spark的全托管大数据处理平台,融合云原生弹性与自动化,提供任务全生命周期管理,让数据工程师专注数据分析。它内置高性能Fusion Engine,性能比开源Spark提升200%,并有成本优化的Celeborn服务。支持计算存储分离、OSS-HDFS兼容、DLF元数据管理,实现一站式的开发体验和Serverless资源管理。适用于数据报表、科学项目等场景,简化开发与运维流程。用户可通过阿里云控制台快速配置和体验EMR Serverless Spark服务。

推荐镜像

更多