シーンの説明
ハイブ データ テーブルのインポートおよびエクスポート関数のコードは次のとおりです。アセンブルを使用して Java プログラムと Spark 関連の依存関係を jar パッケージにパッケージ化し、最後に、spark-submit を使用して jar を実行のためにクラスターに送信します。
public class SparkHiveApplication {
public static void main(String[] args){
long start = System.currentTimeMillis();
String writeSql = "";
SparkConf sparkConf = new SparkConf();
for (String arg : args) {
if (arg.startsWith("WriteSql=")) {
writeSql = arg.replaceFirst("WriteSql=", "");
}
}
SparkSession spark = SparkSession
.builder()
.appName("write data to hive table")
.config(sparkConf)
.enableHiveSupport()
.getOrCreate();
// LOAD DATA LOCAL INPATH '/path/to/file.csv' INTO TABLE target_table PARTITION (field='x')
spark.sql(writeSql);
long end = System.currentTimeMillis();
System.out.println("cost time:" + (end - start));
}
}
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>2.4.8</version>
</dependency>
CDH6.3.2 クラスター (以下、CDH と呼びます) では、プログラムが spark.sql を実行してローカル ディスクの CSV データをハイブ テーブルにインポートすると、例外が発生しますが (以下に示すように)、テーブル データはローカル ディスクにエクスポートされません。ディスクおよび HDFS からのインポートおよびエクスポート機能は正常です。
Caused by: java.lang.IllegalArgumentException: Wrong FS: file:/input/data/training/csv_test1_1301125633652294217_1690451941587.csv, expected: hdfs://nameservice1
at org.apache.hadoop.fs.FileSystem.checkPath(FileSystem.java:649)
データを確認したところ、spark-hive_2.11のバージョンの非互換性が原因であることが判明し、デバッグ中に例外が次々と発生しました(以下の通り)。
Exception in thread "main" org.apache.spark.sql.AnalysisException: org.apache.hadoop.hive.ql.metadata.HiveException: Unable to fetch table csv_test2. Invalid method name: 'get_table_req';
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/hive/ql/metadata/HiveException
at java.lang.Class.getDeclaredConstructors0(Native Method)
最初のローカル ディスク インポート例外は、spark-hive_2.1.1: 2.4.0-cdh6.3.3 を使用して最終的に解決されました。
次に、spark-hive_2.1.1: 2.4.0-cdh6.3.3 依存関係を含む jar パッケージを使用すると、CDP クラスター (別のビッグ データ クラスター) でインポートおよびエクスポートするときに例外がスローされました。依存関係のバージョンをspark-hive_2.11 に変更します。 : 2.4 .8、例外解決。
java.lang.NoSuchMethodException: org.apache.hadoop.hive.ql.metadata.Hive.alterTable(java.lang.String, org.apache.hadoop.hive.ql.metadata.Table, org.apache.hadoop.hive.metastore.api.EnvironmentContext)
現時点で、2 つのクラスターのインポートとエクスポートに関係する一部のコンポーネントのバージョンは次のとおりです。
集まる | スパーク | ハイブ | Javaのspark-hive_2.1 |
---|---|---|---|
CDH | 3.0.x | 2.1.1 | 2.4.0-cdh6.3.3 |
CDP | 3.0.x | 3.1.3 | 2.4.8 |
注: インポートおよびエクスポート操作は、k8s 上の Spark を使用して実行されるため、CDH または CDP クラスターにインストールされている Spark の代わりに、イメージ内の Spark 3.0 が使用されます。
異常原因解析
スパーク.sql は実行時に次の 3 つのことを行う必要があります。
- Spark は最初に hiveMetaStoreClient オブジェクトを作成します。
- 次に、hiveMetaStoreClient メソッドを呼び出して CDH (CDP) の hiveMetastoreServer と通信し、テーブル関連のメタ情報を取得します。
- 取得した情報を元にSQL実行プランを生成し、実際にデータを処理します。
オブジェクト jvm を生成するには、まず完全修飾クラス名を使用して対応するクラス ファイルを検索し、リフレクションを通じてオブジェクトを構築し、次にオブジェクト メソッドを実行する必要があります。問題はここにもあります。パッケージ名とクラス名は同じですが、バージョンが異なると、メソッド名、メソッド パラメータ、メソッドの内容、対応するオカレンス、およびメソッドの実行時にスローされる例外が異なる場合がありInvalid method name: 'get_table_req'
ますjava.lang.NoSuchMethodException
。
シナリオの説明で依存関係のバージョンを変更するということは、実際には、適切な hiveMetastore バージョンを見つけて、jvm にそれを最初にロードさせることを意味します。2.4.0-cdh6.3.3 には内部に hive-metastore:2.1.1-cdh6.3.3 が含まれており、2.4.8 には内部に hive-metastore:1.2.1spark2 が含まれています。
別の解決策
Spark1.4.0 以降のバージョンでは、さまざまなバージョンの Hive Metastore との対話がサポートされています。掲載されているリストは、Spark 3.4.1 と互換性のある Hive Meatstore バージョン 0.12.0 ~ 2.3.9 および 3.0.0 ~ 3.1.3 のものです。さまざまなバージョンの互換性については、公式ドキュメントで確認できます。
異なるバージョンの Hive メタストアとの対話を構成するにはどうすればよいですか?
(1) 内蔵。Spark には組み込みのハイブがあり、アプリケーションの jar パッケージに含まれていない場合、または外部で指定されている場合は、デフォルトで組み込みのハイブが使用されます。Spark のバージョンごとに組み込み Hive のバージョンも異なり、spark3.4.1 には hive2.3.9 が組み込まれ、spark3.0.3 には hive2.3.7 が組み込まれます。スパークシェルでspark.sqlを使用する場合は、組み込みのものを使用する必要があります。これは、Java jarパッケージがなく、コマンドラインで「spark-shell」と入力するだけで起動できるためです。
(2) その場でダウンロードします。構成spark.sql.hive.metastore.version=2.1.1
とspark.sql.hive.metastore.jars=maven
、spark.sql が実行されると、2.1.1 関連の依存関係が Maven ウェアハウスからローカルの /root/.livy/jars パスにダウンロードされます。約 188 個の jar パッケージがあり、合計サイズは約 200M です。ただし、ネットワーク速度が非常に遅い場合、または Maven ウェアハウスに特定の依存関係がない場合、この方法はダウンロードに失敗し、その場でのダウンロードは運用環境には適していません。
(3) バージョンと依存関係のパスを指定します。
- Spark 3.1.0
spark.sql.hive.metastore.version=2.1.1
および より前に構成されていますspark.sql.hive.metastore.jars=/path-to-hive-jars/*
。Spark.sql を実行すると、最初に path-to-hive-jars パスから依存関係が検索されます。 - Spark 3.1.0 以降では、構成
spark.sql.hive.metastore.version=2.1.1
,spark.sql.hive.metastore.jars=path
が必要ですspark.sql.hive.metastore.jars.path=path-to-hive-jars
。「path-to-hive-jars」には HDFS 上のパスを指定できます。詳細については、表を参照してください。
この方法は実稼働環境でも使用できます。
(3) の方法を採用する場合、spark と互換性があり、クラスター ハイブと問題なく通信できるように、事前に正しい依存関係を取得するにはどうすればよいでしょうか?
ハイブ クラスターが Spark バージョンの互換性範囲内にある場合に操作するクラスター。クラスターハイブ/ライブラリの下にあるすべての jar パッケージ (約 200M) を「ポンプ」して Spark するだけです。(それほど大量に使用する必要はありませんが、スクリーニングには実験的テストが必要です)。
以下は、CDH クラスターでインポート操作を実行するときのspark-submit コマンドです。事前にCDHのhive/lib配下のjarパッケージを取り出し、コンテナの/opt/ml/input/data/training/sparkjar/hive-jarsパスにマウントしておきます。
# 在 k8s 容器中执行
/usr/local/spark/bin/spark-submit \
--conf spark.driver.bindAddress=172.16.0.44 \
--deploy-mode client \
--conf spark.sql.hive.metastore.jars=/data/training/sparkjar/hive-jars/* \
--conf spark.sql.hive.metastore.version=2.1.1 \
--properties-file /opt/spark/conf/spark.properties \
--class com.spark.SparkHiveApplication \
local:///data/training/sparkjar/hive-metastore-spark-app-jar-with-dependencies.jar \
WriteSql=TE9BRCBEQVRBIExPQ0FMIElOUEFUSCAnL29wdC9tbC9vdXRwdXQvMTc1NjQ2NDY2MDY3Mzk4NjU3LzE3NTY0NjQ2NjA2NzM5ODY1Ny9wYXJ0LTAwMDAwLWVhYjA2ZWZiLTcwNTktNGI4MS04YmRhLWE3NGE5Yzg3OTY2MS1jMDAwLmNzdicgSU5UTyBUQUJMRSBkdF90aW9uZV90ZXN0XzIwMjIwNzIyIHBhcnRpdGlvbiAocGFydF9udW09JzEnKQ==
プロジェクトと組み合わせると、すべての jar パッケージを確実に入手し、適切な「戦闘」方法を見つけることができるようになります。ここにリストされているものは、Spark タスクに依存関係を追加する 1 つの方法にすぎません。
「痩せる」ように努めてください
アセンブリ jar を作成するときは、spark-hive_2.1 のライフ サイクルを provided に設定します。つまり、依存関係は最終的な jar パッケージに含まれません。クラスターマネージャーは、jar タスクの実行時に依存する jar を独自に提供できるためです。また、Maven 公式 Web サイトにあるSpark-Hiveのライフサイクルは、提供されているとおりに記載されています。
Spark-Hive 依存関係のない jar パッケージのサイズは 9M (以前は 144M) で、インポート操作とエクスポート操作はそれぞれ CDP と CDH で実行されます。結果:
-
CDP クラスターテストに合格しました。
-
CDH クラスター例外。推測では、ネイティブの Spark3 は hive-metastore:2.1.1-cdh6.3.3 と互換性がありません (ディストリビューションはネイティブ バージョンに基づいて変更を行う場合があります)。方法 (3) の構成を使用した後、インポートおよびエクスポート機能は正常です。 。
クラスターがリリース バージョンを使用してデプロイされている場合、コンポーネントはより大きなバージョンと互換性がある可能性が高くなります。さらに、Java jar 関数を頻繁にデバッグする場合、9M サイズによりアップロード時間が短縮され、効率が向上します。
まとめ
Spark によって使用される hiveMetastore は、構成を通じて指定できます。クラスターに付属する依存関係の使用を優先すると、コンポーネントの非互換性の例外をある程度まで減らすことができます。Java jar パッケージでは、アプリケーションの記述方法のみが重要であり、依存関係はクラスターによって提供されるため、jar パッケージと特定のビッグ データ クラスター間の強力なバインディング関係が削除される可能性があります。ただし、外部構成はあくまで解決策であり、エンジニアリングと組み合わせる場合には、現場の要件に応じてさらに実装計画を設計し、実験を行う必要があります。