关于Hudi 0.13.1 Streaming Query 报错

org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat ClassNotFoundException

Keywords: Hudi编译HiveFlink对Hudi进行Streaming QueryHudi包冲突编译Hudi

版本:

Hadoop

3.2.2

Spark

3.2.4

Flink

1.16.1

Hive

3.1.3(后回退版本到3.1.2)

Hudi

0.13.1(后使用Hudi Github master分支-0.14.0)

(此处有包冲突,即Hive用的guava.jar版本为guava-19.0.jar,而Hadoop 3.2.2 版本guava.jar版本为guava-27.0-jre.jar)

一般不建议runtime的Hadoop版本高于hive依赖的版本

场景: 使用Flink SQL 对Hudi表进行Streaming Query

官网介绍:使用streaming-query实时查询Hudi表流式数据

CREATE TABLE t2(
  uuid VARCHAR(20) PRIMARY KEY NOT ENFORCED,
  name VARCHAR(10),
  age INT,
  ts TIMESTAMP(3),
  `partition` VARCHAR(20)
)
PARTITIONED BY (`partition`)
WITH (
  'connector' = 'hudi',
  'path' = 'hdfs://localhost:9000/hudi-warehouse/hudi-t1',
  'table.type' = 'MERGE_ON_READ',
  'read.streaming.enabled' = 'true',  
  'read.start-commit' = '20210316134557', 
  'read.streaming.check-interval' = '4'
);

当使用Flink Client SQL 对Hudi进行 Streaming Query 时,注意官网Note

The bundle jar with hive profile is needed for streaming query, by default the officially released flink bundle is built without hive profile, the jar needs to be built manually, see Build Flink Bundle Jar for more details.

然后我们此时就必须自己通过Hudi源码编译 hudi-flink1.16-bundle-0.13.1.jar

下载Hudi-0.13.1 版本的源码,解压,修改参数编译

但当修改~/hudi-0.13.1/pom.xml

<hadoop.version>3.1.2</hadoop.version>
    <hive.groupid>org.apache.hive</hive.groupid>
    <hive.version>3.1.3</hive.version>

以及 ~/hudi-0.13.1/packaging/hudi-flink-bundle/pom.xml

<hive.version>3.1.3</hive.version>
   ....
   
   <profile>
      <id>flink-bundle-shade-hive3</id>
      <properties>
        <hive.version>3.1.3</hive.version>
        <flink.bundle.hive.scope>compile</flink.bundle.hive.scope>
      </properties>
      <dependencies>
        <dependency>
          <groupId>${hive.groupid}</groupId>
          <artifactId>hive-service-rpc</artifactId>
          <version>${hive.version}</version>
          <scope>${flink.bundle.hive.scope}</scope>
        </dependency>
        <dependency>
          <groupId>${hive.groupid}</groupId>
          <artifactId>hive-standalone-metastore</artifactId>
          <version>${hive.version}</version>
          <scope>${flink.bundle.hive.scope}</scope>
        </dependency>
      </dependencies>
    </profile>

然后

mvn clean install -DskipTests -Pflink-bundle-shade-hive3

时无法构建,报错

[INFO] hudi-hadoop-mr ..................................... FAILURE [  2.121 s]
.....
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project hudi-hadoop-mr: Compilation failure: Compilation failure: 
[ERROR] /Users/kturnura/Packages/hudi-0.13.1/hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop/utils/HoodieInputFormatUtils.java:[92,50] 无法将类 org.apache.hudi.hadHoodieParquetInputFormat中的构造器 HoodieParquetInputFormat应用到给定类型;
[ERROR]   需要: org.apache.hudi.hadoop.HoodieCopyOnWriteTableInputFormat
[ERROR]   找到: 没有参数
[ERROR]   原因: 实际参数列表和形式参数列表长度不同
[ERROR] /Users/kturnura/Packages/hudi-0.13.1/hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop/hive/HoodieCombineHiveInputFormat.java:[846,14] 无法将类 org.apache.huadoop.HoodieParquetInputFormat中的构造器 HoodieParquetInputFormat应用到给定类型;
[ERROR]   需要: org.apache.hudi.hadoop.HoodieCopyOnWriteTableInputFormat
[ERROR]   找到: 没有参数
[ERROR]   原因: 实际参数列表和形式参数列表长度不同
[ERROR] /Users/kturnura/Packages/hudi-0.13.1/hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop/utils/HiveAvroSerializer.java:[302,93] 不兼容的类型: org.apache.hadoopcommon.type.Date无法转换为java.sql.Date
[ERROR] /Users/kturnura/Packages/hudi-0.13.1/hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop/utils/HiveAvroSerializer.java:[305,72] 不兼容的类型: org.apache.hadoopcommon.type.Timestamp无法转换为java.sql.Timestamp
[ERROR] /Users/kturnura/Packages/hudi-0.13.1/hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop/utils/HiveAvroSerializer.java:[309,98] 不兼容的类型: org.apache.hadoopcommon.type.Date无法转换为java.sql.Date
[ERROR] /Users/kturnura/Packages/hudi-0.13.1/hudi-hadoop-mr/src/main/java/com/uber/hoodie/hadoop/HoodieInputFormat.java:[26,8] 无法将类 org.apache.hudi.hadoop.HoodiePatInputFormat中的构造器 HoodieParquetInputFormat应用到给定类型;

解决办法

我们在Github找到了本问题的原因 https://github.com/apache/hudi/pull/7173

时间戳无法被Hive3 获取

解决方法一(提供思路,未能尝试成功)

使用patch 合并Contributor 的代码 https://github.com/apache/hudi/files/11574950/5189.patch.zip到本地源码中

测试使用

git apply --check patch/5189.patch

合并到hudi-0.13.1 源码中打补丁失败

git apply --reject file.patch

手动合并,使用这个命令产生冲突无法合并的文件会在~/hudi-0.13.1/hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop生成 .rej文件,然后手动合并

可以以下链接参照来逐一修改java文件

https://github.com/apache/hudi/pull/7173/files#diff-cd42bec5495e839654687e99670f40d27defe7178bdd347f23db651fc3262bb7

此处比较迷惑的点是由于Git,使用Hudi-0.13.1源码合并Hudi master分支下的patch包。

还有一个就是尝试过直接copy master分支代码到Hudi 0.13版本在hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop的代码,但是有新代码添加,无法成功执行

解决办法 二

使用最新源码,同时回退Hive-3.1.2(这是出现另一个问题时Pflink-bundle-shade-hive3 默认指定hive版本为3.1.2,本人尝试多种方式解决减少冲突时回退了版本,但使用该方法使用 hive 3.1.3 应该也可以解决(因为源码中关于Hive 3.1.3 的时间戳)

出现问题:

  1. 查看许多博客的方法:修改Hudi源码 pom.xml以及~/hudi/packaging/hudi-flink-bundle/pom.xmlhadoop.versionhive.version版本。但仍然会出现guava.jar 冲突。报错:

Caused by: java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkArgument (ZLjava/lang/String;Ljava/lang/Object;)V.

  1. 原因:经过检查发现Hadoop3.1.3 和 hive-3.1.2 的lib下面的guava都是guava-27.0-jre.jar,没有冲突问题。
    那就说明只可能是flink/lib下面添加的上面4个jar包中有jar包编译时,引用的guava版本过低导致的。
    通过源码锁定了hive-exec-3.1.2.jar 引用了guava-19.0.jar 包,并且 flink-sql-connector-hive-3.1.2_2.11-1.12.0.jar 引用了 hive-exec-3.1.2.jar 参考文献
  2. 通过上述参考文献编译Hive-exec-3.1.2.jar 源码并没有解决问题,依然存在冲突

解决方式参考文献

直接编译文件:具体版本根据个人环境调参

mvn clean package -DskipTests -Dcheckstyle.skip -Dspark3.2 -Dflink1.16 -Dscala-2.12 -Dhadoop.version=3.2.2 -Pflink-bundle-shade-hive3

此时打出的jar包中guava.jar 版本依然为19.0 ,而此时hadoop 的guava.jar 包中的 版本为 guava-27.0-jre.jar