专业的编程技术博客社区

网站首页 > 博客文章 正文

数据湖Apache Iceberg本地调试异常分析

baijin 2024-08-30 11:36:36 博客文章 2 ℃ 0 评论

#头号周刊#

1.IDEA本地加载项目红色问题

Iceberg项目load进idea,出现relocated相关的模块异常,且本地gradlew build无异常。

红色的这块classes,是shaded的classes,

目前gradlew配合idea貌似配合得不好,有时候切分支没法自动地识别这些shaded的classes。

所以,一般需要你重新build一遍这写shaded的classes。

解决方案如下:执行bundled-guava里面的build这个task,如图

2.本地测试与Hive metastore有关的异常

2.1 现象

在对Row-Level-Delete功能做测试时,使用了spark3-extendsions模块下的TestDelete.java的测试代码testDeleteFromEmptyTable,但是本地测试会有如下的异常信息。

TestHiveMetastore启动失败

Cannot start TestHiveMetastore
java.lang.RuntimeException: Cannot start TestHiveMetastore
at org.apache.iceberg.hive.TestHiveMetastore.start(TestHiveMetastore.java:119)
at org.apache.iceberg.hive.TestHiveMetastore.start(TestHiveMetastore.java:93)
at org.apache.iceberg.spark.extensions.SparkExtensionsTestBase.startMetastoreAndSpark(SparkExtensionsTestBase.java:42)
...
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.jdo.JDOFatalInternalException: Error creating transactional connection factory
NestedThrowables:
java.lang.reflect.InvocationTargetException
at org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:671)

2.2 原因分析

经过分析发现,测试类TestDelete继承了抽象测试类SparkExtensionsTestBase,使用到了junit的BeforeClass,其中的startMetastoreAndSpark函数有如下信息:

@BeforeClass
public static void startMetastoreAndSpark() {
  SparkTestBase.metastore = new TestHiveMetastore();
  metastore.start(); // Hive元数据的启动
  SparkTestBase.hiveConf = metastore.hiveConf();
  ...
}
跟进到TestHiveMetastore的metastore启动模块如下
public void start(int poolSize) {
try {
  this.hiveLocalDir = createTempDirectory("hive", asFileAttribute(fromString("rwxrwxrwx"))).toFile();
  File derbyLogFile = new File(hiveLocalDir, "derby.log");
  System.setProperty("derby.stream.error.file", derbyLogFile.getAbsolutePath());
  setupMetastoreDB("jdbc:derby:" + getDerbyPath() + ";create=true");
  TServerSocket socket = new TServerSocket(0);
  int port = socket.getServerSocket().getLocalPort();
  this.hiveConf = newHiveConf(port); // a) Hive的配置文件初始化
  this.server = newThriftServer(socket, poolSize, hiveConf);  // b)初始化一个HiveServer实例
  this.executorService = Executors.newSingleThreadExecutor();
  this.executorService.submit(() -> server.serve());
  // in Hive3, setting this as a system prop ensures that it will be picked up whenever a new HiveConf is created
  System.setProperty(HiveConf.ConfVars.METASTOREURIS.varname, hiveConf.getVar(HiveConf.ConfVars.METASTOREURIS));
  this.clientPool = new HiveClientPool(1, hiveConf);
  } catch (Exception e) {
  throw new RuntimeException("Cannot start TestHiveMetastore", e);
  }
}


跟踪newThriftServer函数发现,HiveConf配置文件内的"javax.jdo.option.ConnectionUserName"参数的值本应该是"APP",而被修改成了"hive",且Hive在元数据使用derby数据库初始化(楼下URL)的时候使用的"APP"库存储的元数据,导致始终报错如下,且通过本地链接derby数据库查阅"APP"库下如下的Query是能成功的。

https://github.com/apache/iceberg/blob/master/hive-metastore/src/test/resources/hive-schema-3.1.0.derby.sql
Caused by: javax.jdo.JDOException: Exception thrown when executing query : SELECT 'org.apache.hadoop.hive.metastore.model.MVersionTable' AS NUCLEUS_TYPE,A0.SCHEMA_VERSION,A0.VERSION_COMMENT,A0.VER_ID FROM VERSION A0
NestedThrowables:
java.sql.SQLSyntaxErrorException: Table/View 'VERSION' does not exist.


既然如此,那就说明HiveConf的获取有配置信息的异常,重新回溯到查找Hive配置文件初始化的过程,见org.apache.hadoop.hive.conf.HiveConf的initialize函数,发现如下

private void initialize(Class<?> cls) {
  hiveJar = (new JobConf(cls)).getJar();
  ...
  // Overlay hive-site.xml if it exists
  if (hiveSiteURL != null) {
  addResource(hiveSiteURL);
  }
  ...
}

在DEBUG时候发现,初始化HiveConf过程中,hivesiteURL不为空,且其值为我本地机器的"/Users/dovezhang/software/hive/hive/conf/hive-site.xml",本地的hive-site.xml部分配置如下:

<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://localhost:3306/hive2?createDatabaseIfNotExist=true&useSSL=false</value>
<description>the URL of the MySQL database</description>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>hive</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>hive</value>
</property>

导致了HiveConf的创建时候,“javax.jdo.option.ConnectionUserName”被修改,然后去derby库内寻找hive.version表时异常。

故,注释本地HIVE_HOME的全局环境变量的配置,问题解决。

其中还尝试过在gradlew中添加mysql-connector-java的依赖和修改“hive-schema-3.1.0.derby.sql”内的库名("APP"->"HIVE"),但是繁琐且不解决根本问题,问题的根源在于HiveConf的初始化修改了默认库名导致的HiveMetastore启动失败。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表