背景
Amazon EMR 6.15.0 上で Spark ジョブを実行中、S3 Tables Catalog(Iceberg)を使って S3 上のテーブルデータを処理したところ、以下のような Avro 関連エラーが発生しました:
java.lang.NoSuchMethodError: 'org.apache.avro.LogicalTypes$TimestampNanos org.apache.avro.LogicalTypes.timestampNanos()'
原因
- EMR 6.15.0 標準で提供されている Iceberg (1.4.0-amzn-0) が 古い Avro を参照してしまう
- クラスパス優先順で EMR 標準のライブラリが先に読み込まれるため、
timestampNanosが見つからない
対応内容
1. Fat JAR(uber JAR)の作成
-
アプリケーション JAR に必要な依存をすべてまとめる
- Iceberg(例: 1.6.1 以上)
- Avro(1.11.4 に固定)
- S3 Tables Catalog(0.1.9 以上)
-
Maven Shade Plugin を使用して、依存をすべて統合した 1 つの JAR を作成
-
例:
data_cahngeng_emr_v2.3.jar
2. Fat JAR の配置
- S3 にアップロードして Step から参照
s3://example-bucket/jar/data_cahngeng_emr_v2.3.jar
3. MWAA から EMR Step を実行
-
spark-submitで fat JAR を直接指定
"Args": [
"spark-submit",
"--class", "com.example.Main",
"--conf", "spark.driver.extraClassPath=data_cahngeng_emr_v2.3.jar",
"--conf", "spark.executor.extraClassPath=data_cahngeng_emr_v2.3.jar",
"s3://example-bucket/jars/data_cahngeng_emr_v2.3.jar"
]
ポイント
- Spark が S3 から自動で JAR を Driver / Executor に配布
-
extraClassPathを設定することで EMR 標準の古い Iceberg より優先して読み込む
効果
- EMR 6.15.0 標準の Iceberg / Avro によるバージョン競合を回避
-
timestampNanosエラーが解消 - 依存バージョンをプロジェクト側で明確に管理可能
まとめ
- EMR 6.15.0 標準 JAR は古く競合しやすいため、fat JAR にまとめて依存を明示的に指定するのが安全
- MWAA から EMR Step で実行する場合、S3 に置いた fat JAR を指定するだけで運用可能
- 今後も EMR 上で Iceberg を使う際のベストプラクティスとして有効
補足
■S3テーブルへ接続する際にウェアハウスやテーブル名などをどこに設定するか問題
①ジョブ単位で動的に設定したい場合
ソースコードで SparkSession.builder().config(...) に書く
例)
spark = SparkSession.builder()
.appName("IcebergWithS3Tables")
.config("spark.sql.extensions", "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions")
.config("spark.sql.catalog.s3tbl", "org.apache.iceberg.spark.SparkCatalog")
.config("spark.sql.catalog.s3tbl.catalog-impl", "software.amazon.s3tables.iceberg.S3TablesCatalog")
.config("spark.sql.catalog.s3tbl.warehouse", "s3://your-s3tables-bucket/")
.config("spark.sql.catalog.s3tbl.io-impl", "org.apache.iceberg.aws.s3.S3FileIO")
.getOrCreate()
②クラスター全体で統一したい場合
spark-defaults.conf や --conf で渡す
例)
spark-submit \
--conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
--conf spark.sql.catalog.s3tbl=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.s3tbl.catalog-impl=software.amazon.s3tables.iceberg.S3TablesCatalog \
--conf spark.sql.catalog.s3tbl.warehouse=s3://your-s3tables-bucket/ \
--conf spark.sql.catalog.s3tbl.io-impl=org.apache.iceberg.aws.s3.S3FileIO \
your-app.jar
💡 Tips:
- Maven Shade Plugin で作る fat JAR は依存のバージョン固定と排他設定も同時にできるので、複雑な依存関係の整理に便利!