Spark.sql 実行時のバージョンの非互換性を解決する方法

シーンの説明

ハイブ データ テーブルのインポートおよびエクスポート関数のコードは次のとおりです。アセンブルを使用して 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 つのことを行う必要があります。

  1. Spark は最初に hiveMetaStoreClient オブジェクトを作成します。
  2. 次に、hiveMetaStoreClient メソッドを呼び出して CDH (CDP) の hiveMetastoreServer と通信し、テーブル関連のメタ情報を取得します。
  3. 取得した情報を元に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.0spark.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 パッケージと特定のビッグ データ クラスター間の強力なバインディング関係が削除される可能性があります。ただし、外部構成はあくまで解決策であり、エンジニアリングと組み合わせる場合には、現場の要件に応じてさらに実装計画を設計し、実験を行う必要があります。

おすすめ

転載: blog.csdn.net/yy_diego/article/details/132356563