1 概述
開發調試spark程序時,因為要訪問開啟kerberos認證的hive/hbase/hdfs等組件,每次調試都需要打jar包,上傳到服務器執行特別影響工作效率,所以調研了下如何在windows環境用idea直接跑spark任務的方法,本文旨在記錄配置本地調試環境中遇到的問題及解決方案。
2 環境
Jdk 1.8.0
Spark 2.1.0
Scala 2.11.8
Hadoop 2.6.0-cdh5.12.1
Hive 1.1.0-cdh5.12.1
環境搭建略,直接看本地調試spark程序遇到的問題。
注意:若要訪問遠端hadoop集群服務,需將hosts配置到windows本地。
3 測試代碼
測試主類,功能spark sql讀取開啟Kerberos認證的遠端hive數據
import org.apache.spark.sql.SparkSession
object SparkTest{
def main(args: Array[String]): Unit = {
//kerberos認證
initKerberos()
val spark = SparkSession.builder().master("local[2]").appName("SparkTest")
.enableHiveSupport()
.getOrCreate()
spark.sql("show databases").show()
spark.sql("use testdb")
spark.sql("show tables").show()
val sql = "select * from infodata.sq_dim_balance where dt=20180625 limit 10"
spark.sql(sql).show()
spark.stop()
}
def initKerberos(): Unit ={
//kerberos權限認證
val path = RiskControlUtil.getClass.getClassLoader.getResource("").getPath
val principal = PropertiesUtil.getProperty("kerberos.principal")
val keytab = PropertiesUtil.getProperty("kerberos.keytab")
val conf = new Configuration
System.setProperty("java.security.krb5.conf", path + "krb5.conf")
conf.addResource(new Path(path + "hbase-site.xml"))
conf.addResource(new Path(path + "hdfs-site.xml"))
conf.addResource(new Path(path + "hive-site.xml"))
conf.set("hadoop.security.authentication", "Kerberos")
conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem")
UserGroupInformation.setConfiguration(conf)
UserGroupInformation.loginUserFromKeytab(principal, path + keytab)
println("login user: "+UserGroupInformation.getLoginUser())
}
}
4 問題及解決方案
4.1 問題1
java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.
winutils.exe是在Windows系統上需要的hadoop調試環境工具,里面包含一些在Windows系統下調試hadoop、spark所需要的基本的工具類
出現上面的問題,可能是因為windows環境下缺少winutils.exe文件或者版本不兼容的原因。
解決辦法:
(1)下載winutils,注意需要與hadoop的版本相對應。
hadoop2.6版本可以在這里下載https://github.com/amihalik/hadoop-common-2.6.0-bin
由於配置的測試集群是hadoop2.6,所以我在這里下載的是2.6.0版本的。下載后,將其解壓,包括:hadoop.dll和winutils.exe
(2)配置環境變量
①增加系統變量HADOOP_HOME,值是下載的zip包解壓的目錄,我這里解壓后將其重命名為hadoop-common-2.6.0
②在系統變量path里增加%HADOOP_HOME%\bin
③重啟電腦,使環境變量配置生效,上述問題即可解決。
添加系統變量HADOOP_HOME
編輯系統變量Path,添加%HADOOP_HOME%\bin;
4.2 問題2
如果hadoop集群開啟了kerberos認證,本地調試也需要進行認證,否則會報權限錯誤;
將權限相關配置文件放入工程的resource目錄,如下所示
認證代碼如下:
def initKerberos(): Unit ={
//kerberos權限認證
val path = RiskControlUtil.getClass.getClassLoader.getResource("").getPath
val principal = PropertiesUtil.getProperty("kerberos.principal")
val keytab = PropertiesUtil.getProperty("kerberos.keytab")
val conf = new Configuration
System.setProperty("java.security.krb5.conf", path + "krb5.conf")
conf.addResource(new Path(path + "hbase-site.xml"))
conf.addResource(new Path(path + "hdfs-site.xml"))
conf.addResource(new Path(path + "hive-site.xml"))
conf.set("hadoop.security.authentication", "Kerberos")
conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem")
UserGroupInformation.setConfiguration(conf)
UserGroupInformation.loginUserFromKeytab(principal, path + keytab)
println("login user: "+UserGroupInformation.getLoginUser())
}
4.3 問題3
Caused by: java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.createDirectoryWithMode0(Ljava/lang/String;I)V
網上說目前錯誤的解決辦法還沒有解決,采用一種臨時的方式來解決,解決的辦法是:通過下載你的CDH的版本的源碼(http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.12.1-src.tar.gz),
在對應的文件下,hadoop2.6.0-cdh5.12.1-src\hadoop-common-project\hadoop- common\src\main\java\org\apache\hadoop\io\nativeio下NativeIO.java 復制到對應的Eclipse的project(復制的過程中需要注意一點,就是在當前的工程下創建相同的包路徑,這里的包路徑org.apache.hadoop.io.nativeio再將對應NativeIO.java文件復制到對應的包路徑下即可。)
Windows的唯一方法用於檢查當前進程的請求,在給定的路徑的訪問權限,所以我們先給以能進行訪問,我們自己先修改源代碼,return true 時允許訪問。修改NativeIO.java文件中的557行的代碼,如下所示:
源代碼如下:
public static boolean access(String path, AccessRight desiredAccess)
throws IOException {
return access0(path, desiredAccess.accessRight());
}
修改后的代碼如下:
public static boolean access(String path, AccessRight desiredAccess)
throws IOException {
return true;
//return access0(path, desiredAccess.accessRight());
}
再次執行,這個錯誤修復。
4.4 問題4
Caused by: java.io.FileNotFoundException: File /tmp/hive does not exist
這個錯誤是說臨時目錄/tmp/hive需要有全部權限,即777權限,創建/tmp/hive 目錄,用winutils.exe對目錄賦權,如下
C:\>D:\spark_hadoop\hadoop-common\hadoop-common-2.6.0\bin\winutils.exe chmod -R 777 D:\tmp\hive
C:\>D:\spark_hadoop\hadoop-common\hadoop-common-2.6.0\bin\winutils.exe chmod -R 777 \tmp\hive
4.5 問題5
Exception in thread "main" java.lang.NoSuchFieldError: METASTORE_CLIENT_SOCKET_LIFETIME
OR
Exception in thread "main" java.lang.IllegalArgumentException: Unable to instantiate SparkSession with Hive support because Hive classes are not found
原因是spark sql 讀取hive元數據需要的字段METASTORE_CLIENT_SOCKET_LIFETIME hive1.2.0開始才有,而我們引用的cdh版本的hive為1.1.0-cdh5.12.1,沒有該字段,故報錯。
Spark SQL when configured with a Hive version lower than 1.2.0 throws a java.lang.NoSuchFieldError for the field METASTORE_CLIENT_SOCKET_LIFETIME because this field was introduced in Hive 1.2.0 so its not possible to use Hive metastore version lower than 1.2.0 with Spark. The details of the Hive changes can be found here: https://issues.apache.org/jira/browse/HIVE-9508
解決方法,引入第三方依賴
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>2.1.0</version>
</dependency>
4.6 問題6
Exception in thread "main" java.lang.RuntimeException: org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.ClassNotFoundException: org.apache.hadoop.hive.ql.security.authorization.StorageBasedAuthorizationProvider,org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory
解決方法,將window idea引入的hive-site.xml進行如下修改
<!--<property>-->
<!--<name>hive.security.authorization.manager</name>-->
<!--<value>org.apache.hadoop.hive.ql.security.authorization.StorageBasedAuthorizationProvider,org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory</value>-->
<!--</property>-->
<property>
<name>hive.security.authorization.manager</name>
<value>org.apache.hadoop.hive.ql.security.authorization.DefaultHiveAuthorizationProvider</value>
</property>
5 總結
總結重要的幾點就是:
(1) 配置HADOOP_HOME,內帶winutils.exe 和 hadoop.dll 工具;
(2) 引入hive-site.xml等配置文件,開發kerberos認證邏輯;
(3) 本地重寫NativeIO.java類;
(4) 給臨時目錄/tmp/hive賦予777權限;
(5) 引入第三方依賴spark-hive_2.11,要與spark版本對應;
(6) 本地hive-site.xml將hive.security.authorization.manager改為默認manager
最后提醒一點,本地調試只是問了開發階段提高效率,避免每次修改都要打包提交到服務器運行,但調試完,還是要打包到服務器環境運行測試,沒問題才能上線。
至此,spark本地調試程序配置完成,以后就可以愉快地在本地調試spark on hadoop程序了。
6 參考
https://abgoswam.wordpress.com/2016/09/16/getting-started-with-spark-on-windows-10-part-2/