异常还原
需要将 mysql 数据导入 hive。先按网上教程安装 sqoop,尝试连接 mysql,程序抛出异常(果然 hadoop 家族所有成员,从安装配置到运行,没一个让人省心的)
$ sqoop list-databases --connect jdbc:mysql://localhost:3306 --username xxx --password 'xxx'
20/08/05 22:31:24 INFO sqoop.Sqoop: Running Sqoop version: 1.4.7
20/08/05 22:31:25 WARN tool.BaseSqoopTool: Setting your password on the command-line is insecure. Consider using -P instead.
20/08/05 22:31:25 INFO manager.MySQLManager: Preparing to use a MySQL streaming resultset.
Exception in thread "main" java.lang.NoSuchMethodError: org.hsqldb.DatabaseURL.parseURL(Ljava/lang/String;ZZ)Lorg/hsqldb/persist/HsqlProperties;
at org.hsqldb.jdbc.JDBCDriver.getConnection(Unknown Source)
at org.hsqldb.jdbc.JDBCDriver.connect(Unknown Source)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:247)
at org.apache.sqoop.manager.SqlManager.makeConnection(SqlManager.java:904)
at org.apache.sqoop.manager.GenericJdbcManager.getConnection(GenericJdbcManager.java:59)
at org.apache.sqoop.manager.CatalogQueryManager.listDatabases(CatalogQueryManager.java:57)
at org.apache.sqoop.tool.ListDatabasesTool.run(ListDatabasesTool.java:49)
at org.apache.sqoop.Sqoop.run(Sqoop.java:147)
at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
at org.apache.sqoop.Sqoop.runSqoop(Sqoop.java:183)
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:234)
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:243)
at org.apache.sqoop.Sqoop.main(Sqoop.java:252)
排查过程
咋回事呢?Stackoverflow 找到了类似问题(stackoverflow.com/questions/7… ),回答是 make sure that you have only one version of hsqldb on your classpath, 意思是我的 $CLASSPATH 下有两个 jar 包导致了这个异常。用 echo $CLASSPATH 查看一下:
.:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext:/usr/lib/jvm/java-8-openjdk-amd64/lib/dt.jar:/usr/lib/jvm/java-8-openjdk-amd64/lib/tools.jar:/usr/local/hive/apache-hive-3.1.2-bin/lib:/usr/lib/jvm/java-8-openjdk-amd64/lib:/usr/local/sqoop/lib(好长。。。)
检查了这些路径,确实只有一个 hsqldb-xxx.jar 包啊,百思不得解。。。
Google 上看了些其它类似问题(不是 sqoop,但异常的名称大致类似),解答大都是反映问题出在是 classpath 上。想来这也合理,毕竟异常中提示找不到 method,或许确实应该从 classpath 中找思路。修改 $CLASSPATH 环境变量,加入 $SQOOP_HOME/lib, $SQOOP_HOME/lib/xxx.jar, $HADOOP_HOME/lib 均无济于事,真是邪门了。
一筹莫展下,试图从 sqoop 命令脚本($SQOOP_HOME/sqoop)中找到些异常的蛛丝马迹。该脚本最末一行内容如下:
exec ${HADOOP_COMMON_HOME}/bin/hadoop org.apache.sqoop.Sqoop "$@"
亦即 sqoop 命令执行时调用了 hadoop,因此运行时的 classpath 事实上要加上 $HADOOP_CLASSPATH。而后者这个变量在之前安装 hadoop 时已在 ~/.bashrc 中初始化为 export HADOOP_CLASSPATH=$(find $HADOOP_HOME -name '*.jar' | xargs echo | tr ' ' ':')。它会不会有冲突的 hsql jar 包呢?检查:
$ find $HADOOP_HOME -name '*.jar' | grep hsqldb
/usr/local/hadoop/share/hadoop/mapreduce/lib-examples/hsqldb-2.0.0.jar
就是它!果然找到了它!将此路径的 hsqldb 更名后,再启动 sqoop 即可正常连接 mysql。
几个思考
- 两个冲突的 jar 包
/usr/local/sqoop/lib/hsqldb-1.8.0.10.jar,/usr/local/hadoop/share/hadoop/mapreduce/lib-examples/hsqldb-2.0.0.jar都是 sqoop hadoop 各自安装时自带的,且 sqoop 要依赖 hadoop。如果存在冲突就无法运行,为啥要在安装包带上呢?这个安装包咋包装的 - hadoop 家族所有程序(hive, sqoop, hdfs 等)的 executable 都是调用了 hadoop 的 shell 脚本,hadoop 本身的运行时环境对它们都适用
- 问题难以时,可以尝试在脚本中添加 echo 输出中间内容