AWS EMR 上的 avro 错误
avro error on AWS EMR
我正在使用 spark-redshift (https://github.com/databricks/spark-redshift),它使用 avro 进行传输。
从 Redshift 读取没问题,而写入时我得到
Caused by: java.lang.NoSuchMethodError: org.apache.avro.generic.GenericData.createDatumWriter(Lorg/apache/avro/Schema;)Lorg/apache/avro/io/DatumWriter
尝试使用 Amazon EMR 4.1.0 (Spark 1.5.0) 和 4.0.0 (Spark 1.4.1)。
做不到
import org.apache.avro.generic.GenericData.createDatumWriter
要么,只是
import org.apache.avro.generic.GenericData
我正在使用 Scala shell
尝试下载其他几个 avro-mapred 和 avro jar,尝试设置
{"classification":"mapred-site","properties":{"mapreduce.job.user.classpath.first":"true"}},{"classification":"spark-env","properties":{"spark.executor.userClassPathFirst":"true","spark.driver.userClassPathFirst":"true"}}
并将这些 jar 添加到 spark 类路径。可能需要以某种方式调整 Hadoop (EMR)。
这是否给任何人敲响了警钟?
spark-redshift
这里是维护者。
其他 EMR 用户在使用更新版本的 spark-avro
库(spark-redshift
依赖)时遇到了类似的错误。简而言之,问题似乎是 EMR 的旧版本 Avro 优先于 spark-avro
所需的新版本。在 https://github.com/databricks/spark-avro/issues/91, an issue that seems to match the exception reported here, one user suggested embedding the Avro JARs with their application code: https://github.com/databricks/spark-avro/issues/91#issuecomment-142543149
这里是来自 EMR 的 Jonathan。部分问题在于 Hadoop 依赖于 Avro 1.7.4,并且完整的 Hadoop 类路径包含在 EMR 上的 Spark 路径中。可能会帮助我们将 Hadoop 的 Avro 依赖升级到 1.7.7,以便它与 Spark 的 Avro 依赖相匹配,虽然我有点担心这可能会破坏其他东西,但我还是可以尝试一下。
顺便说一句,我在您的示例 EMR 集群配置中注意到的一个问题是您使用的是 "spark-env" 配置分类,而 "spark-defaults" 分类适合设置 spark。{ driver,executor}.userClassPathFirst。不过,我不确定这本身是否能解决您的问题。
仅供参考 - Alex Nastetsky
的解决方法
从主节点删除 jar
find / -name "*avro*jar" 2> /dev/null -print0 | xargs -0 -I file sudo rm file
从从属节点删除 jar
yarn node -list | sed 's/ .*//g' | tail -n +3 | sed 's/:.*//g' | xargs -I node ssh node "find / -name "*avro*jar" 2> /dev/null -print0 | xargs -0 -I file sudo rm file
按照 Jonathan 的建议正确设置配置也值得一试。
EMR 中与 Avro 相关的运行时冲突错误非常常见。
Avro 被广泛使用,很多 jar 都将它作为依赖项。
我在 'NoSuchMethodError' 或不同的 Avro 版本中用不同的方法看到了这个问题的几个变体。
我没有用'spark.executor.userClassPathFirst'标志解决它,因为我得到了LinkageError。
这是为我解决冲突的解决方案:
- 使用 Intellij 的依赖分析器(Maven 插件)将 Avro 从导致冲突的所有依赖项中排除。
设置 EMR 时,添加一个 bootstrap 操作,它调用一个 bash 脚本来下载特定的 Avro JAR:
#!/bin/bash
mkdir -p /home/hadoop/lib/
cd /home/hadoop/lib/
wget http://apache.spd.co.il/avro/avro-1.8.0/java/avro-1.8.0.jar
设置EMR时,增加如下配置:
[
{"classification":"spark-defaults", "properties":{
"spark.driver.extraLibraryPath":"/home/hadoop/lib/avro-1.8.0.jar:/usr/lib/hadoop/*:/usr/lib/hadoop/../hadoop-hdfs/*:/usr/lib/hadoop/../hadoop-mapreduce/*:/usr/lib/hadoop/../hadoop-yarn/*:/etc/hive/conf:/usr/lib/hadoop/../hadoop-lzo/lib/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*",
"spark.executor.extraClassPath":"/home/hadoop/lib/avro-1.8.0.jar:/usr/lib/hadoop/*:/usr/lib/hadoop/../hadoop-hdfs/*:/usr/lib/hadoop/../hadoop-mapreduce/*:/usr/lib/hadoop/../hadoop-yarn/*:/etc/hive/conf:/usr/lib/hadoop/../hadoop-lzo/lib/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*",
"spark.driver.extraClassPath":"/home/hadoop/lib/avro-1.8.0.jar:/usr/lib/hadoop/*:/usr/lib/hadoop/../hadoop-hdfs/*:/usr/lib/hadoop/../hadoop-mapreduce/*:/usr/lib/hadoop/../hadoop-yarn/*:/etc/hive/conf:/usr/lib/hadoop/../hadoop-lzo/lib/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*"},
"configurations":[]}
]
如您所见,我必须在现有库中添加新库。否则它不起作用。
我正在使用 spark-redshift (https://github.com/databricks/spark-redshift),它使用 avro 进行传输。
从 Redshift 读取没问题,而写入时我得到
Caused by: java.lang.NoSuchMethodError: org.apache.avro.generic.GenericData.createDatumWriter(Lorg/apache/avro/Schema;)Lorg/apache/avro/io/DatumWriter
尝试使用 Amazon EMR 4.1.0 (Spark 1.5.0) 和 4.0.0 (Spark 1.4.1)。 做不到
import org.apache.avro.generic.GenericData.createDatumWriter
要么,只是
import org.apache.avro.generic.GenericData
我正在使用 Scala shell 尝试下载其他几个 avro-mapred 和 avro jar,尝试设置
{"classification":"mapred-site","properties":{"mapreduce.job.user.classpath.first":"true"}},{"classification":"spark-env","properties":{"spark.executor.userClassPathFirst":"true","spark.driver.userClassPathFirst":"true"}}
并将这些 jar 添加到 spark 类路径。可能需要以某种方式调整 Hadoop (EMR)。
这是否给任何人敲响了警钟?
spark-redshift
这里是维护者。
其他 EMR 用户在使用更新版本的 spark-avro
库(spark-redshift
依赖)时遇到了类似的错误。简而言之,问题似乎是 EMR 的旧版本 Avro 优先于 spark-avro
所需的新版本。在 https://github.com/databricks/spark-avro/issues/91, an issue that seems to match the exception reported here, one user suggested embedding the Avro JARs with their application code: https://github.com/databricks/spark-avro/issues/91#issuecomment-142543149
这里是来自 EMR 的 Jonathan。部分问题在于 Hadoop 依赖于 Avro 1.7.4,并且完整的 Hadoop 类路径包含在 EMR 上的 Spark 路径中。可能会帮助我们将 Hadoop 的 Avro 依赖升级到 1.7.7,以便它与 Spark 的 Avro 依赖相匹配,虽然我有点担心这可能会破坏其他东西,但我还是可以尝试一下。
顺便说一句,我在您的示例 EMR 集群配置中注意到的一个问题是您使用的是 "spark-env" 配置分类,而 "spark-defaults" 分类适合设置 spark。{ driver,executor}.userClassPathFirst。不过,我不确定这本身是否能解决您的问题。
仅供参考 - Alex Nastetsky
的解决方法从主节点删除 jar
find / -name "*avro*jar" 2> /dev/null -print0 | xargs -0 -I file sudo rm file
从从属节点删除 jar
yarn node -list | sed 's/ .*//g' | tail -n +3 | sed 's/:.*//g' | xargs -I node ssh node "find / -name "*avro*jar" 2> /dev/null -print0 | xargs -0 -I file sudo rm file
按照 Jonathan 的建议正确设置配置也值得一试。
EMR 中与 Avro 相关的运行时冲突错误非常常见。 Avro 被广泛使用,很多 jar 都将它作为依赖项。 我在 'NoSuchMethodError' 或不同的 Avro 版本中用不同的方法看到了这个问题的几个变体。
我没有用'spark.executor.userClassPathFirst'标志解决它,因为我得到了LinkageError。
这是为我解决冲突的解决方案:
- 使用 Intellij 的依赖分析器(Maven 插件)将 Avro 从导致冲突的所有依赖项中排除。
设置 EMR 时,添加一个 bootstrap 操作,它调用一个 bash 脚本来下载特定的 Avro JAR:
#!/bin/bash
mkdir -p /home/hadoop/lib/ cd /home/hadoop/lib/ wget http://apache.spd.co.il/avro/avro-1.8.0/java/avro-1.8.0.jar
设置EMR时,增加如下配置:
[ {"classification":"spark-defaults", "properties":{ "spark.driver.extraLibraryPath":"/home/hadoop/lib/avro-1.8.0.jar:/usr/lib/hadoop/*:/usr/lib/hadoop/../hadoop-hdfs/*:/usr/lib/hadoop/../hadoop-mapreduce/*:/usr/lib/hadoop/../hadoop-yarn/*:/etc/hive/conf:/usr/lib/hadoop/../hadoop-lzo/lib/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*", "spark.executor.extraClassPath":"/home/hadoop/lib/avro-1.8.0.jar:/usr/lib/hadoop/*:/usr/lib/hadoop/../hadoop-hdfs/*:/usr/lib/hadoop/../hadoop-mapreduce/*:/usr/lib/hadoop/../hadoop-yarn/*:/etc/hive/conf:/usr/lib/hadoop/../hadoop-lzo/lib/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*", "spark.driver.extraClassPath":"/home/hadoop/lib/avro-1.8.0.jar:/usr/lib/hadoop/*:/usr/lib/hadoop/../hadoop-hdfs/*:/usr/lib/hadoop/../hadoop-mapreduce/*:/usr/lib/hadoop/../hadoop-yarn/*:/etc/hive/conf:/usr/lib/hadoop/../hadoop-lzo/lib/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*"}, "configurations":[]} ]
如您所见,我必须在现有库中添加新库。否则它不起作用。