解决执行 spark.sql 时版本不兼容的一种方式

场景描述

hive 数据表的导入导出功能部分代码如下所示,使用 assemble 将 Java 程序和 spark 相关依赖一起打成 jar 包,最后 spark-submit 提交 jar 到集群执行。

public class SparkHiveApplication {

    public static void main(String[] args){

        long start = System.currentTimeMillis();
        String writeSql = "";
        SparkConf sparkConf = new SparkConf();

        for (String arg : args) {
            if (arg.startsWith("WriteSql=")) {
                writeSql = arg.replaceFirst("WriteSql=", "");
            }
        }

        SparkSession spark = SparkSession
                .builder()
                .appName("write data to hive table")
                .config(sparkConf)
                .enableHiveSupport()
                .getOrCreate();

        // LOAD DATA LOCAL INPATH '/path/to/file.csv' INTO TABLE target_table PARTITION (field='x')
        spark.sql(writeSql);

        long end = System.currentTimeMillis();
        System.out.println("cost time:" + (end - start));
    }
}
  <dependency>
      <groupId>org.apache.spark</groupId>
      <artifactId>spark-hive_2.11</artifactId>
      <version>2.4.8</version>
  </dependency>

在CDH6.3.2 集群(后面称CDH),当程序执行 spark.sql 导入本地磁盘 csv 数据到 hive 表时出现异常(如下),但导出表数据到本地磁盘、从 HDFS 导入导出功能却都是正常的。

Caused by: java.lang.IllegalArgumentException: Wrong FS: file:/input/data/training/csv_test1_1301125633652294217_1690451941587.csv, expected: hdfs://nameservice1
        at org.apache.hadoop.fs.FileSystem.checkPath(FileSystem.java:649)

查资料判定是 spark-hive_2.11 版本不兼容导致的,在调试的过程中陆续又出现异常(如下)

Exception in thread "main" org.apache.spark.sql.AnalysisException: org.apache.hadoop.hive.ql.metadata.HiveException: Unable to fetch table csv_test2. Invalid method name: 'get_table_req';
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/hive/ql/metadata/HiveException
        at java.lang.Class.getDeclaredConstructors0(Native Method)

最终使用 spark-hive_2.1.1: 2.4.0-cdh6.3.3 解决了最初的本地磁盘导入异常。

接着用包含 spark-hive_2.1.1: 2.4.0-cdh6.3.3 依赖的 jar 包在 CDP 集群(另一个大数据集群)执行导入导出时又抛了异常,修改依赖版本为 spark-hive_2.11: 2.4.8 ,异常解决。

java.lang.NoSuchMethodException: org.apache.hadoop.hive.ql.metadata.Hive.alterTable(java.lang.String, org.apache.hadoop.hive.ql.metadata.Table, org.apache.hadoop.hive.metastore.api.EnvironmentContext)

此时两个集群中参与导入导出的部分组件版本如下:

集群sparkhiveJava 中的 spark-hive_2.1
CDH3.0.x2.1.12.4.0-cdh6.3.3
CDP3.0.x3.1.32.4.8

备注:导入导出操作采用 spark on k8s 方式执行,所以使用是镜像中的 spark 3.0 而非 CDH 、CDP 集群上安装的 spark。

异常原因分析

spark.sql 执行时要做三件事情:

  1. spark 首先创建 hiveMetaStoreClient 对象;
  2. 再调用 hiveMetaStoreClient 的方法去跟 CDH(CDP) 中的 hiveMetastoreServer 通信获取表相关元信息。
  3. 根据获取到的信息生成 sql 的执行计划,真正处理数据。

生成对象 jvm 首先需要通过全限定类名找到对应 Class 文件,通过反射的方式构造出对象再执行对象方法。问题也在这个地方:包名+类名相同,不同版本可能方法名、方法参数、方法内容不同,对应的出现 Invalid method name: 'get_table_req' java.lang.NoSuchMethodException 以及方法执行时抛出异常。

场景描述中更换依赖版本实际上是在找适配的 hiveMetastore 版本,并且让 jvm 率先加载到。2.4.0-cdh6.3.3 内部包含 hive-metastore:2.1.1-cdh6.3.3,2.4.8内部包含 hive-metastore:1.2.1spark2。

另一种解决方式

spark1.4.0 以后的版本支持和不同版本的 Hive Metastore 交互。列表贴的是 spark 3.4.1 兼容的 hive meatstore 版本 0.12.0 到 2.3.9 和 3.0.0 到 3.1.3。不同版本兼容可在官方文档查看

在这里插入图片描述

怎么配置和不同版本 hive metastore 交互?

(1)内置。spark 内置了 hive,如果应用程序 jar 包中也没有带,也没有外部指定时,默认使用内置的。不同版本 spark 内置的 hive 版本也有差异,spark3.4.1 内置 hive2.3.9,spark3.0.3 内置 hive2.3.7。在 spark-shell 中使用 spark.sql 时应该用的是内置的,因为那会没有 Java jar 包,启动也仅仅是在命令行敲了“spark-shell”。

(2)当场下载。配置spark.sql.hive.metastore.version=2.1.1 spark.sql.hive.metastore.jars=maven ,当执行spark.sql 时会先从 maven 仓库下载 2.1.1 相关的依赖到本地 /root/.livy/jars 路径下,大概 188 个 jar 包,总大小 200M 左右。但这种方式当网速很慢或者 maven 仓库没有某些依赖时会下载失败,而且当场下载也不适合生产环境。

(3)指定版本以及依赖的路径。

  • spark 3.1.0 之前配置 spark.sql.hive.metastore.version=2.1.1 spark.sql.hive.metastore.jars=/path-to-hive-jars/* 。执行 spark.sql 时就会率先从 path-to-hive-jars 路径下寻找依赖。
  • spark 3.1.0 之后需要配置 spark.sql.hive.metastore.version=2.1.1 spark.sql.hive.metastore.jars=pathspark.sql.hive.metastore.jars.path=path-to-hive-jars。“path-to-hive-jars” 可以是 HDFS 上的路径,具体细节看表格介绍。

​ 这种方式可以用在生产环境中。

如果采用方式(3)怎么提前获取到正确的依赖,既能跟 spark 兼容又能和集群 hive 通信没问题?

要操作哪个集群如果该集群 hive 在 spark 版本兼容的范围内。直接将集群 hive/lib 下的全部 jar 包(200M左右)“怼” 给 spark 就可以了。(可能用不了那么多,但筛选需要做实验测试)。

下面是在 CDH 集群执行导入操作时的 spark-submit 命令。提前将 CDH 的 hive/lib 下的 jar 包拿出来挂载到容器的 /opt/ml/input/data/training/sparkjar/hive-jars 路径下。

#  在 k8s 容器中执行
/usr/local/spark/bin/spark-submit \
--conf spark.driver.bindAddress=172.16.0.44 \
--deploy-mode client \
--conf spark.sql.hive.metastore.jars=/data/training/sparkjar/hive-jars/* \
--conf spark.sql.hive.metastore.version=2.1.1 \
--properties-file /opt/spark/conf/spark.properties \
--class com.spark.SparkHiveApplication \
local:///data/training/sparkjar/hive-metastore-spark-app-jar-with-dependencies.jar \
WriteSql=TE9BRCBEQVRBIExPQ0FMIElOUEFUSCAnL29wdC9tbC9vdXRwdXQvMTc1NjQ2NDY2MDY3Mzk4NjU3LzE3NTY0NjQ2NjA2NzM5ODY1Ny9wYXJ0LTAwMDAwLWVhYjA2ZWZiLTcwNTktNGI4MS04YmRhLWE3NGE5Yzg3OTY2MS1jMDAwLmNzdicgSU5UTyBUQUJMRSBkdF90aW9uZV90ZXN0XzIwMjIwNzIyIHBhcnRpdGlvbiAocGFydF9udW09JzEnKQ==

与工程结合时肯定能获取到全部 jar 包以及找到合适的“怼”方式。这里列举的只是一种向 spark 任务添加依赖的方式。

尝试打“瘦”包

在创建 assembly jar 的时候,将 spark-hive_2.1 的生命周期设置为 provided,即不将该依赖打入最后的 jar 包。因为在运行 jar 任务时集群管理器可以自己提供依赖的 jar。而且 spark-hive 在 maven 官网的生命周期就被给定是 provided。

没有 spark-hive 依赖的 jar 包大小 9M (之前是 144M),分别在 CDP 和 CDH 上执行导入导出操作。结果:

  • CDP 集群测试通过。

  • CDH 集群异常。猜测是原生 spark3 和 hive-metastore:2.1.1-cdh6.3.3 不兼容(发行版有时会在原生基础上做改动),改用方式(3)中的配置后导入导出功能正常。

如果集群采用发行版部署,大版本下各组件兼容的可能性更大些。而且当频繁调试 Java jar 功能时 9M 大小缩短了上传时间,效率也变高了。

小结

通过配置的方式可以指定 spark 使用的 hiveMetastore。优先使用集群自带的依赖可以在一定程度上减少组件不兼容异常。Java jar 包中只管应用程序怎么写,依赖让集群提供,可以解除 jar 包与某个大数据集群的强绑定关系。但外部配置只是一种解决方案,如果要与工程结合还需要根据场景需求进一步设计实现方案并做实验。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误提示是Spark SQL在Hive上执行出现的错误,错误代码为3,可能是由于Hadoop执行出现了问题导致的。建议检查Hadoop的配置和运行状态,以及Spark SQL和Hive的版本兼容性等问题。 ### 回答2: 当在Spark SQL on Hive中遇到"failed: execution error, return code 3 from org.apache.hadoop..ql.exec…. "的错误,可能有几个原因导致此错误。 首先,这个错误通常与Hive的执行器有关。Hive的执行器负责将Hive查询转换为底层的MapReduce任务或Tez任务来执行查询。如果执行器遇到问题,可能会导致此错误。可以尝试检查Hive配置以确保执行器配置正确,并重新启动Hive服务。 另外,此错误也可能是由于输入输出路径的问题导致的。当在Hive中执行查询,需要指定输入和输出路径。如果路径无效或权限不足,可能会导致此错误。可以确保输入输出路径正确,并且具有正确的权限。 还有一种可能性是由于查询本身或查询配置的问题导致。查询可能包含不受支持的语法或语义。可以尝试使用不同的查询进行测试,以确定是否只有特定的查询触发此错误。还可以检查Hive配置以确保所有必需的参数正确设置,并与Hive版本兼容。 最后,此错误可能由于集群的其他问题,如网络问题或资源不足引起。可以尝试重新启动集群并检查集群的健康状态。 总的来说,"failed: execution error, return code 3 from org.apache.hadoop..ql.exec…."的错误可能由于Hive执行器、路径问题、查询问题或集群问题导致。可以通过检查Hive配置、查询和集群状态,逐步排除这些可能的原因,以解决此错误。 ### 回答3: 当Spark SQL运行在Hive上,报错"failed: execution error, return code 3 from org.apache.hadoop.hive.ql.exec"通常是由于Hive执行任务发生了错误。 这个错误可能是由于以下几个原因导致的: 1. 数据库表或分区不存在:如果你的SQL查询中引用了不存在的表或分区,那么就会出现这个错误。请确保表和分区存在并正确地命名。 2. 文件路径错误:如果你的SQL查询中引用了不存在的文件路径,那么也会导致这个错误。请检查文件路径,并确保文件可用。 3. 内存不足:当Hive执行任务,可能会因为内存不足而导致错误。可以尝试增加内存分配给Hive,或者优化查询以减少内存消耗。 4. 数据类型不匹配:如果你的SQL查询中使用了不匹配的数据类型,也会导致这个错误。请确保查询中使用的数据类型与表定义的数据类型一致。 5. 数据分区冲突:如果你的表是以分区方式存储的,并且查询条件与分区键不匹配,那么会出现这个错误。请检查查询条件,并确保与分区键匹配。 解决这个错误的方法包括: 1. 确保表和分区存在,文件路径正确,数据类型匹配,分区键匹配等。 2. 增加Hive的内存分配量。 3. 优化查询,减少内存消耗。 4. 检查Hive日志文件,查找更详细的错误信息,以帮助定位问题。 综上所述,当出现"failed: execution error, return code 3 from org.apache.hadoop.hive.ql.exec"错误,我们应该仔细检查可能导致错误的各种原因,并采取适当的解决措施来解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值