背景和問題
在使用Spark SQL創建寫入Hudi表的時候出現如下錯誤(錯誤很長,無關部分省略):
ERROR XJ040: Failed to start database 'metastore_db' with class loader org.apache.spark.sql.hive.client.IsolatedClientLoader$$anon$1@1ebb10fb, see the next exception for details.
...
ERROR XSDB6: Another instance of Derby may have already booted the database /xxx/metastore_db.
...
原因是Derby作爲嵌入式數據庫,不支持多用戶同時訪問。但作者並沒有同時使用多個spark-sql/spark-shell來操作。百思不得其解。
經過調研得到兩個可行的解決方案:
- 升級Spark使用的JDK爲JDK17。方法爲下載解壓JDK17到各個spark節點,然後配置各個節點的
$SPARK_HOME/conf/spark-env.sh
增加export JAVA_HOME=/path/to/jdk17
。最後重新運行任務。 - 放棄使用Derby,使用Hive metastore或者直接使用MySQL作爲metastore的存儲後端。
兩種方式均可解決此問題。下面藉此問題,引申出配置Spark metastore的方法。
環境信息
- JDK 8
- Spark 3.x
- MySQL 8.x
- Hive 3.x
Spark SQL自身metastore使用MySQL替換Derby
安裝和部署MySQL的步驟因篇幅所限這裏省略。可參考其他相關文檔。
配置MySQL JDBC驅動
下載和環境中MySQL版本對應的MySQL JDBC驅動,複製到各個Spark節點的$SPARK_HOME/jars
目錄中。
MySQL配置
創建metastore專用的數據庫:
create database metastore character set utf8mb4;
創建訪問metastore元數據專用的用戶和權限配置:
create user 'metastore'@'%' identified by 'password';
然後給metastore
用戶metastore
數據庫的訪問權限:
grant all privileges on `metastore`.* to 'metastore'@'%' identified by 'password';
flush privileges;
在MySQL中導入metastore schema
在MySQL所在節點下載Hive 3.x版本,解壓後找到scripts/metastore/upgrade/mysql/hive-schema-版本號.mysql.sql
。然後使用metastore
用戶進入MySQL執行:
use metastore;
source /path/to/hive/scripts/metastore/upgrade/mysql/hive-schema-版本號.mysql.sql;
配置hive-site.xml
編寫如下hive-site.xml
文件,放置在所有Spark節點$SPARK_HOME/conf
目錄中。
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://mysql_server_hostname:3306/metastore</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>metastore</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>password</value>
</property>
<property>
<name>datanucleus.autoCreateSchema</name>
<value>false</value>
</property>
<property>
<name>datanucleus.fixedDatastore</name>
<value>true</value>
</property>
注意:生產環境爲了保證MySQL Schema穩定,避免意外的數據庫結構變更,需要設置
datanucleus.fixedDatastore
爲true
。如果配置datanucleus.autoCreateSchema
爲true
,datanucleus.fixedDatastore
爲false
,MySQL metastore庫的表結構會自動創建。無需再導入metastore schema。
參考鏈接:https://docs.databricks.com/data/metastores/external-hive-metastore.html
到這裏爲止使用MySQL替換Derby作爲metastore元數據存儲配置完畢。
使用Hive metastore
除了上面的方式之外,生產環境更爲通用和穩定的解決方案爲統一使用Hive的metastore。下面列出Spark使用Hive metastore的配置步驟。
配置spark-defaults.conf
編輯$SPARK_HOME/conf/spark-defaults.conf
文件,增加如下內容。然後將修改過後的文件分發到所有Spark節點的conf
目錄。
spark.sql.hive.metastore.jars /path/to/standalone-metastore/*
spark.sql.hive.metastore.version 3.0
配置項解釋:
- spark.sql.hive.metastore.jars: 指定Hive standalone-metastore jar文件所在的路徑
- spark.sql.hive.metastore.version: Hive的版本號
配置hive-site.xml
複製包含如下內容的hive-site.xml
到所有Spark節點的$SPARK_HOME/conf
目錄。
<configuration>
<property>
<name>hive.exec.scratchdir</name>
<value>/tmp/spark</value>
</property>
<property>
<name>hive.metastore.client.connect.retry.delay</name>
<value>5</value>
</property>
<property>
<name>hive.metastore.client.socket.timeout</name>
<value>1800</value>
</property>
<property>
<name>hive.metastore.uris</name>
<value>thrift://metastore_host:9083</value>
</property>
<property>
<name>hive.server2.enable.doAs</name>
<value>false</value>
</property>
<property>
<name>hive.server2.thrift.http.port</name>
<value>10002</value>
</property>
<property>
<name>hive.server2.thrift.port</name>
<value>10016</value>
</property>
<property>
<name>hive.server2.transport.mode</name>
<value>binary</value>
</property>
<property>
<name>metastore.catalog.default</name>
<value>hive</value>
</property>
</configuration>
需要注意的是需要修改hive.metastore.uris
爲真實環境下metastore安裝所在節點的URL。hive.server2.thrift.http.port
和hive.server2.thrift.port
也修改爲對應服務的端口號。這些配置項可以從Hive集羣的hive-site.xml
文件中複製出來直接使用。
到這裏Spark使用Hive metastore的配置已完成。
本博客爲作者原創,歡迎大家參與討論和批評指正。如需轉載請註明出處。