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。

这是为我解决冲突的解决方案:

  1. 使用 Intellij 的依赖分析器(Maven 插件)将 Avro 从导致冲突的所有依赖项中排除。
  2. 设置 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
    
  3. 设置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":[]}
    ]
    

如您所见,我必须在现有库中添加新库。否则它不起作用。