Spark,Fat Jar的替代方案

11
我知道至少两种方法可以将依赖项导入Spark EMR作业。其中一种是创建一个“fat” jar文件,另一种是使用--packages选项在spark submit中指定要使用的包。
制作“fat” jar文件需要很长时间进行压缩。这正常吗?约10分钟。我们配置有误吗?
命令行选项是不错的选择,但容易出错。
还有其他替代方案吗?我希望(已经存在)一种方法可以将依赖项列表包含在gradle的jar文件中,并下载它们。这是可能的吗?还有其他替代方案吗?
更新:我发布了一个部分答案。我的原始问题中没有明确说明的一件事是,当您具有不同版本的相同jar文件时,会出现依赖冲突的情况。 更新 感谢回复,建议减少依赖项的数量或在可能的情况下使用provided。针对这个问题,假设我们只有运行所需的最少依赖项。

1
我通常使用SBT。使用sbt-assembly并利用provided依赖关系限定符,您最终可以获得相当合理的fat JAR。您能否分享一下构建文件?没有这些文件很难理解为什么您的fat JAR构建需要这么长时间。 - stefanobaghino
请问您能否解释一下您是如何构建jar包的?您是否使用AWS Codebuild?您的项目架构是什么样子的?您的jar包大小是多少? - eliasah
我正在使用Gradle构建我的jar文件,并将所有依赖项压缩到其中。 - Carlos Bribiescas
4个回答

8

如果需要通过某个应用程序启动Spark作业,则可以使用Spark launcher。使用Spark launcher,您可以配置jar路径,无需创建fat.jar来运行应用程序。

使用fat-jar需要安装Java,并且启动Spark应用程序需要执行java -jar [your-fat-jar-here]。如果您想从Web应用程序启动应用程序,要自动化它是很困难的。

使用SparkLauncher,您可以选择从另一个应用程序(例如上面的Web应用程序)启动Spark应用程序。这只是更容易。

import org.apache.spark.launcher.SparkLauncher

SparkLauncher extends App {

val spark = new SparkLauncher()
.setSparkHome("/home/knoldus/spark-1.4.0-bin-hadoop2.6")
.setAppResource("/home/knoldus/spark_launcher-assembly-1.0.jar")
.setMainClass("SparkApp")
.setMaster("local[*]")
.launch();
spark.waitFor();

}

代码: https://github.com/phalodi/Spark-launcher

这里:

  • setSparkHome(“/home/knoldus/spark-1.4.0-bin-hadoop2.6”)用于设置Spark Home,内部使用它来调用Spark submit。

  • .setAppResource(“/home/knoldus/spark_launcher-assembly-1.0.jar”)用于指定我们的Spark应用程序的JAR文件。

  • .setMainClass(“SparkApp”)是Spark程序的入口点,即驱动程序。

  • .setMaster(“local[*]”)设置主节点的地址,在本地机器上运行。

  • .launch()简单地启动我们的Spark应用程序。

SparkLauncher与java -jar fat-jar相比有什么优势?

https://jaceklaskowski.gitbooks.io/mastering-apache-spark/spark-SparkLauncher.html

https://spark.apache.org/docs/2.0.0/api/java/org/apache/spark/launcher/SparkLauncher.html

http://henningpetersen.com/post/22/running-apache-spark-jobs-from-applications


3
例如,在Cloudera的集群上,所有节点上都有一些库集,这些库将作为驱动程序和执行程序的类路径可用。 这些库包括spark-core、spark-hive、hadoop等。
版本是由Cloudera分组的,例如,您有spark-core-cdh5.9.0,其中cdh5.9.0后缀表示该后缀的所有库都已由Cloudera验证可以正常配合使用。 您应该做的唯一一件事就是使用相同组后缀的库,您将不会遇到任何类路径冲突。 这样可以设置应用程序中的依赖项,配置为Maven提供的范围,因此它们不会成为大型JAR的一部分,但是可以从节点的类路径中解析出来。
您没有写出您有什么类型的集群,但也许您可以使用类似的方法。
maven shade插件可用于创建大型JAR,还允许设置要包含在列表中以及未在列表中的库。

我认为这个回答中描述了类似的内容Spark, Alternative to Fat Jar,但使用S3作为依赖项存储。


1
HubSpot提供了一个(部分)解决方案:SlimFast。您可以在此处找到解释http://product.hubspot.com/blog/the-fault-in-our-jars-why-we-stopped-building-fat-jars,并且您可以在此处找到代码https://github.com/HubSpot/SlimFast
实际上,它会将所有可能需要的jar包存储在s3上,因此在构建时不会打包jar包,但在运行时会从s3获取它们。因此,您的构建速度很快,下载时间也不长。
我认为,如果这还具有上传时避免冲突的功能,则它将是一个完美的解决方案。

0

创建这个fat jar确实需要很长时间。我通过删除运行时不需要的依赖项来进行了一些优化,但这真的很痛苦。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接