Practice data lake iceberg レッスン 30 mysql->iceberg、異なるクライアントにはタイムゾーンの問題があります

シリーズ記事ディレクトリ

Practice Data Lake iceberg レッスン 1 はじめに
Practice Data Lake iceberg レッスン 2 Iceberg は Hadoop の基礎となるデータ形式に基づいています
実践 data lake
iceberg sqlclient で、SQL を使用して Kafka から iceberg にデータを読み取ります (バージョンを flink1.12.7 にアップグレードします)
実践 data lake iceberg レッスン 5 ハイブ カタログの特徴演習データ lake iceberg レッスン 6 kafka からiceberg への書き込み
失敗問題解決の演習データファイル演習データ lake iceberg レッスン 10 スナップショット 削除演習データ lake iceberg レッスン 11 テスト パーティション テーブルの整合性 プロセス (数値の作成、テーブルの作成、マージ、およびスナップショットの削除)演習データ lake iceberg レッスン 12 カタログとは 演習データlake iceberg レッスン 13 メタデータデータファイルよりも何倍も大きい演習 data lake iceberg レッスン 14 データマージ (時間の経過とともにメタデータが拡張する問題を解決するため)演習 data lake iceberg レッスン 15 spark インストールと統合 iceberg (jersey パッケージの競合)演習 data lake iceberg レッスン 16 spark3 Door による氷山の認識










演習 data lake iceberg レッスン 17 Hadoop2.7、spark3 on yarn run iceberg 構成
演習 data lake iceberg 演習 18 複数のクライアントが iceberg とやり取りする 開始コマンド (よく使われるコマンド)
演習 data lake iceberg レッスン 19 flink count iceberg , 結果が出ない問題の
演習 data lake iceberg レッスン 20 flink + iceberg CDC シナリオ (バージョンの問題、テスト失敗)
練習データ lake iceberg レッスン 21 flink1.13.5 + iceberg0.131 CDC (テスト成功 INSERT、変更操作失敗)
練習データ lake iceberg レッスン 22 flink1.13.5 + iceberg0. 131 CDC (CRUD テスト成功)
練習データ lake iceberg レッスン 23 flink-sql
チェックポイントから練習データ lake iceberg を再起動する レッスン 24 iceberg メタデータの詳細 練習データ
lake iceberg を分析する レッスン 25 flink sql をバックグラウンドで実行する 追加、削除、変更の効果
実践 data lake iceberg レッスン 26 チェックポイントの設定方法
実践 data lake iceberg レッスン 27 Flink cdc テスト プログラムの失敗 再起動: 前回のチェックポイントから再起動して作業を続行できる
実践 data lake iceberg レッスン 28 公共の倉庫に存在しないパッケージをローカルにデプロイする倉庫はdata lake iceberg を実践するレッスン29
flink の jobId をエレガントかつ効率的に取得する方法



序文

mysql->flink-sql-cdc->アイスバーグ. flink からデータ時刻を確認しても問題ありませんが、spark-sql からはタイム ゾーンが +8 になっています。この問題を記録する

ここに画像の説明を挿入

最終的な解決策: ソース テーブルにはタイムゾーンがなく、ダウンストリーム テーブルにはローカル タイムゾーンを設定する必要があるため、問題はありません。


1. Spark は氷山データを照会し、都市部のため、日付に 8 を追加します。

1. Spark SQL は、日付を含むフィールドについて iceberg にクエリを実行し、タイムゾーンに関するエラーを報告します

java.lang.IllegalArgumentException: Cannot handle timestamp without timezone fields in Spark. Spark does not natively support this type but if you would like to handle all timestamps as timestamp with timezone set 'spark.sql.iceberg.handle-timestamp-without-timezone' to true. This will not change the underlying values stored but will change their displayed values in Spark. For more information please see https://docs.databricks.com/spark/latest/dataframes-datasets/dates-timestamps.html#ansi-sql-and-spark-sql-timestamps
        at org.apache.iceberg.relocated.com.google.common.base.Preconditions.checkArgument(Preconditions.java:142)
        at org.apache.iceberg.spark.source.SparkBatchScan.readSchema(SparkBatchScan.java:127)
        at org.apache.spark.sql.execution.datasources.v2.PushDownUtils$.pruneColumns(PushDownUtils.scala:136)
        at org.apache.spark.sql.execution.datasources.v2.V2ScanRelationPushDown$$anonfun$applyColumnPruning$1.applyOrElse(V2ScanRelationPushDown.scala:191)
        at org.apache.spark.sql.execution.datasources.v2.V2ScanRelationPushDown$$anonfun$applyColumnPruning$1.applyOrElse(V2ScanRelationPushDown.scala:184)
        at org.apache.spark.sql.catalyst.trees.TreeNode.$anonfun$transformDownWithPruning$1(TreeNode.scala:481)
        at org.apache.spark.sql.catalyst.trees.CurrentOrigin$.withOrigin(TreeNode.scala:82)
        at org.apache.spark.sql.catalyst.trees.TreeNode.transformDownWithPruning(TreeNode.scala:481)
        at org.apache.spark.sql.catalyst.plans.logical.LogicalPlan.org$apache$spark$sql$catalyst$plans$logical$AnalysisHelper$$super$transformDownWithPruning(LogicalPlan.scala:30)
        at org.apache.spark.sql.catalyst.plans.logical.AnalysisHelper.transformDownWithPruning(AnalysisHelper.scala:267)
        at org.apache.spark.sql.catalyst.plans.logical.AnalysisHelper.transformDownWithPruning$(AnalysisHelper.scala:263)
        at org.apache.spark.sql.catalyst.plans.logical.LogicalPlan.transformDownWithPruning(LogicalPlan.scala:30)
        at org.apache.spark.sql.catalyst.plans.logical.LogicalPlan.transformDownWithPruning(LogicalPlan.scala:30)
        at org.apache.spark.sql.catalyst.trees.TreeNode.transformDown(TreeNode.scala:457)
        at org.apache.spark.sql.catalyst.trees.TreeNode.transform(TreeNode.scala:425)
        at org.apache.spark.sql.execution.datasources.v2.V2ScanRelationPushDown$.applyColumnPruning(V2ScanRelationPushDown.scala:184)
        at org.apache.spark.sql.execution.datasources.v2.V2ScanRelationPushDown$.apply(V2ScanRelationPushDown.scala:39)
        at org.apache.spark.sql.execution.datasources.v2.V2ScanRelationPushDown$.apply(V2ScanRelationPushDown.scala:35)
        at org.apache.spark.sql.catalyst.rules.RuleExecutor.$anonfun$execute$2(RuleExecutor.scala:211)
        at scala.collection.LinearSeqOptimized.foldLeft(LinearSeqOptimized.scala:126)
        at scala.collection.LinearSeqOptimized.foldLeft$(LinearSeqOptimized.scala:122)
        at scala.collection.immutable.List.foldLeft(List.scala:91)
        at org.apache.spark.sql.catalyst.rules.RuleExecutor.$anonfun$execute$1(RuleExecutor.scala:208)
        at org.apache.spark.sql.catalyst.rules.RuleExecutor.$anonfun$execute$1$adapted(RuleExecutor.scala:200)
        at scala.collection.immutable.List.foreach(List.scala:431)
        at org.apache.spark.sql.catalyst.rules.RuleExecutor.execute(RuleExecutor.scala:200)
        at org.apache.spark.sql.catalyst.rules.RuleExecutor.$anonfun$executeAndTrack$1(RuleExecutor.scala:179)
        at org.apache.spark.sql.catalyst.QueryPlanningTracker$.withTracker(QueryPlanningTracker.scala:88)
        at org.apache.spark.sql.catalyst.rules.RuleExecutor.executeAndTrack(RuleExecutor.scala:179)
        at org.apache.spark.sql.execution.QueryExecution.$anonfun$optimizedPlan$1(QueryExecution.scala:138)
        at org.apache.spark.sql.catalyst.QueryPlanningTracker.measurePhase(QueryPlanningTracker.scala:111)
        at org.apache.spark.sql.execution.QueryExecution.$anonfun$executePhase$1(QueryExecution.scala:196)
        at org.apache.spark.sql.SparkSession.withActive(SparkSession.scala:775)
        at org.apache.spark.sql.execution.QueryExecution.executePhase(QueryExecution.scala:196)
        at org.apache.spark.sql.execution.QueryExecution.optimizedPlan$lzycompute(QueryExecution.scala:134)
        at org.apache.spark.sql.execution.QueryExecution.optimizedPlan(QueryExecution.scala:130)
        at org.apache.spark.sql.execution.QueryExecution.assertOptimized(QueryExecution.scala:148)
        at org.apache.spark.sql.execution.QueryExecution.$anonfun$executedPlan$1(QueryExecution.scala:166)
        at org.apache.spark.sql.execution.QueryExecution.withCteMap(QueryExecution.scala:73)
        at org.apache.spark.sql.execution.QueryExecution.executedPlan$lzycompute(QueryExecution.scala:163)
        at org.apache.spark.sql.execution.QueryExecution.executedPlan(QueryExecution.scala:163)
        at org.apache.spark.sql.execution.SQLExecution$.$anonfun$withNewExecutionId$5(SQLExecution.scala:101)
        at org.apache.spark.sql.execution.SQLExecution$.withSQLConfPropagated(SQLExecution.scala:163)
        at org.apache.spark.sql.execution.SQLExecution$.$anonfun$withNewExecutionId$1(SQLExecution.scala:90)
        at org.apache.spark.sql.SparkSession.withActive(SparkSession.scala:775)
        at org.apache.spark.sql.execution.SQLExecution$.withNewExecutionId(SQLExecution.scala:64)
        at org.apache.spark.sql.hive.thriftserver.SparkSQLDriver.run(SparkSQLDriver.scala:69)
        at org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver.processCmd(SparkSQLCLIDriver.scala:384)
        at org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver.$anonfun$processLine$1(SparkSQLCLIDriver.scala:504)
        at org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver.$anonfun$processLine$1$adapted(SparkSQLCLIDriver.scala:498)
        at scala.collection.Iterator.foreach(Iterator.scala:943)
        at scala.collection.Iterator.foreach$(Iterator.scala:943)
        at scala.collection.AbstractIterator.foreach(Iterator.scala:1431)
        at scala.collection.IterableLike.foreach(IterableLike.scala:74)
        at scala.collection.IterableLike.foreach$(IterableLike.scala:73)
        at scala.collection.AbstractIterable.foreach(Iterable.scala:56)
        at org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver.processLine(SparkSQLCLIDriver.scala:498)
        at org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver$.main(SparkSQLCLIDriver.scala:287)
        at org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver.main(SparkSQLCLIDriver.scala)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.spark.deploy.JavaMainApplication.start(SparkApplication.scala:52)
        at org.apache.spark.deploy.SparkSubmit.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:955)
        at org.apache.spark.deploy.SparkSubmit.doRunMain$1(SparkSubmit.scala:180)
        at org.apache.spark.deploy.SparkSubmit.submit(SparkSubmit.scala:203)
        at org.apache.spark.deploy.SparkSubmit.doSubmit(SparkSubmit.scala:90)
        at org.apache.spark.deploy.SparkSubmit$$anon$2.doSubmit(SparkSubmit.scala:1043)
        at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:1052)
        at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)

2.プロンプトに従ってタイムゾーンを削除します

セットspark.sql.iceberg.handle-timestamp-without-timezone=真;


spark-sql (default)> set `spark.sql.iceberg.handle-timestamp-without-timezone`=true;
key     value
spark.sql.iceberg.handle-timestamp-without-timezone     true
Time taken: 0.016 seconds, Fetched 1 row(s)
spark-sql (default)> select * from stock_basic2_iceberg_sink;
i       ts_code symbol  name    area    industry        list_date       actural_controller      update_time     update_timestamp
0       000001.SZ       000001  平安银行        深圳    银行    19910403        NULL    2022-04-14 03:53:24     2022-04-21 00:58:59
1       000002.SZ       000002  万科A   深圳    全国地产        19910129        NULL    2022-04-14 03:53:31     2022-04-21 00:59:06
4       000006.SZ       000006  深振业A 深圳    区域地产        19920427        深圳市人民政府国有资产监督管理委员会    NULL    NULL
2       000004.SZ       000004  国华网安        深圳    软件服务        19910114        李映彤  2022-04-14 03:53:34     2022-04-21 00:59:11
3       000005.SZ       000005  ST星源  深圳    环境保护        19901210        郑列列,丁芃     2022-04-14 03:53:40     2022-04-22 00:59:15
Time taken: 1.856 seconds, Fetched 5 row(s)

データ レイクの時間は明らかに mysql の時間と一致しません。火花がチェックされた氷山の時間が 8 時間大幅に増加しました。
ここに画像の説明を挿入

結論: 単純にタイム ゾーンに移動することはできません

3. ローカル タイムゾーンを変更する

SET `table.local-time-zone` = 'Asia/Shanghai';

セットspark.sql.iceberg.handle-timestamp-without-timezone= true; 後

次に、タイムゾーンを設定し、それが無効であることがわかりました:

上海のタイムゾーンに設定:


spark-sql (default)> SET `table.local-time-zone` = 'Asia/Shanghai';
key     value
table.local-time-zone   'Asia/Shanghai'
Time taken: 0.014 seconds, Fetched 1 row(s)
spark-sql (default)>  select * from stock_basic2_iceberg_sink;
i       ts_code symbol  name    area    industry        list_date       actural_controller      update_time     update_timestamp
0       000001.SZ       000001  平安银行        深圳    银行    19910403        NULL    2022-04-14 03:53:24     2022-04-21 00:58:59
1       000002.SZ       000002  万科A   深圳    全国地产        19910129        NULL    2022-04-14 03:53:31     2022-04-21 00:59:06
4       000006.SZ       000006  深振业A 深圳    区域地产        19920427        深圳市人民政府国有资产监督管理委员会    NULL    NULL
2       000004.SZ       000004  国华网安        深圳    软件服务        19910114        李映彤  2022-04-14 03:53:34     2022-04-21 00:59:11
3       000005.SZ       000005  ST星源  深圳    环境保护        19901210        郑列列,丁芃     2022-04-14 03:53:40     2022-04-22 00:59:15
Time taken: 0.187 seconds, Fetched 5 row(s)

utc タイムゾーンに設定:

spark-sql (default)>  SET `table.local-time-zone` = 'UTC';
key     value
table.local-time-zone   'UTC'
Time taken: 0.015 seconds, Fetched 1 row(s)
spark-sql (default)>  select * from stock_basic2_iceberg_sink;
i       ts_code symbol  name    area    industry        list_date       actural_controller      update_time     update_timestamp
0       000001.SZ       000001  平安银行        深圳    银行    19910403        NULL    2022-04-14 03:53:24     2022-04-21 00:58:59
1       000002.SZ       000002  万科A   深圳    全国地产        19910129        NULL    2022-04-14 03:53:31     2022-04-21 00:59:06
4       000006.SZ       000006  深振业A 深圳    区域地产        19920427        深圳市人民政府国有资产监督管理委员会    NULL    NULL
2       000004.SZ       000004  国华网安        深圳    软件服务        19910114        李映彤  2022-04-14 03:53:34     2022-04-21 00:59:11
3       000005.SZ       000005  ST星源  深圳    环境保护        19901210        郑列列,丁芃     2022-04-14 03:53:40     2022-04-22 00:59:15
Time taken: 0.136 seconds, Fetched 5 row(s)

タイム ゾーンを設定します。
テスト対象の spark.sql.session.timeZone が無効であることがわかりました

2. flink-sql を使用してクエリを実行し、時間が問題ないことを確認します

結論: 時間のセマンティクスは mysql 側と一致しています。

  1. Flink SQL 側のクエリ結果:
Flink SQL> select i,ts_code,update_time,update_timestamp from stock_basic2_iceberg_sink;

ここに画像の説明を挿入
2. mysql 側のクエリ結果:
ここに画像の説明を挿入
結論: 時間セマンティクスは mysql 側のものと一致しています。

3.タイムゾーンをソーステーブルに強制的に追加し、エラーを報告する

タイムスタンプを TIMESTAMP_LTZ に変更します


        String createSql = "CREATE TABLE stock_basic_source(\n" +
                "  `i`  INT NOT NULL,\n" +
                "  `ts_code`     CHAR(10) NOT NULL,\n" +
                "  `symbol`   CHAR(10) NOT NULL,\n" +
                "  `name` char(10) NOT NULL,\n" +
                "  `area`   CHAR(20) NOT NULL,\n" +
                "  `industry`   CHAR(20) NOT NULL,\n" +
                "  `list_date`   CHAR(10) NOT NULL,\n" +
                "  `actural_controller`   CHAR(100),\n" +
                "  `update_time`   TIMESTAMP_LTZ\n," +
                "  `update_timestamp`   TIMESTAMP_LTZ\n," +
                "    PRIMARY KEY(i) NOT ENFORCED\n" +
                ") WITH (\n" +
                "  'connector' = 'mysql-cdc',\n" +
                "  'hostname' = 'hadoop103',\n" +
                "  'port' = '3306',\n" +
                "  'username' = 'xxxxx',\n" +
                "  'password' = 'XXXx',\n" +
                "  'database-name' = 'xxzh_stock',\n" +
                "  'table-name' = 'stock_basic2'\n" +
                ")" ;

実行エラー、

Caused by: java.lang.IllegalArgumentException: Unable to convert to TimestampData from unexpected value '1649879611000' of type java.lang.Long
	at com.ververica.cdc.debezium.table.RowDataDebeziumDeserializeSchema$12.convert(RowDataDebeziumDeserializeSchema.java:504)
	at com.ververica.cdc.debezium.table.RowDataDebeziumDeserializeSchema$17.convert(RowDataDebeziumDeserializeSchema.java:641)
	at com.ververica.cdc.debezium.table.RowDataDebeziumDeserializeSchema.convertField(RowDataDebeziumDeserializeSchema.java:626)
	at com.ververica.cdc.debezium.table.RowDataDebeziumDeserializeSchema.access$000(RowDataDebeziumDeserializeSchema.java:63)
	at com.ververica.cdc.debezium.table.RowDataDebeziumDeserializeSchema$16.convert(RowDataDebeziumDeserializeSchema.java:611)
	at com.ververica.cdc.debezium.table.RowDataDebeziumDeserializeSchema$17.convert(RowDataDebeziumDeserializeSchema.java:641)
	at com.ververica.cdc.debezium.table.RowDataDebeziumDeserializeSchema.extractAfterRow(RowDataDebeziumDeserializeSchema.java:146)
	at com.ververica.cdc.debezium.table.RowDataDebeziumDeserializeSchema.deserialize(RowDataDebeziumDeserializeSchema.java:121)
	at com.ververica.cdc.connectors.mysql.source.reader.MySqlRecordEmitter.emitElement(MySqlRecordEmitter.java:118)
	at com.ververica.cdc.connectors.mysql.source.reader.MySqlRecordEmitter.emitRecord(MySqlRecordEmitter.java:100)
	at com.ververica.cdc.connectors.mysql.source.reader.MySqlRecordEmitter.emitRecord(MySqlRecordEmitter.java:54)
	at org.apache.flink.connector.base.source.reader.SourceReaderBase.pollNext(SourceReaderBase.java:128)
	at org.apache.flink.streaming.api.operators.SourceOperator.emitNext(SourceOperator.java:294)
	at org.apache.flink.streaming.runtime.io.StreamTaskSourceInput.emitNext(StreamTaskSourceInput.java:69)
	at org.apache.flink.streaming.runtime.io.StreamOneInputProcessor.processInput(StreamOneInputProcessor.java:66)
	at org.apache.flink.streaming.runtime.tasks.StreamTask.processInput(StreamTask.java:423)
	at org.apache.flink.streaming.runtime.tasks.mailbox.MailboxProcessor.runMailboxLoop(MailboxProcessor.java:204)
	at org.apache.flink.streaming.runtime.tasks.StreamTask.runMailboxLoop(StreamTask.java:684)
	at org.apache.flink.streaming.runtime.tasks.StreamTask.executeInvoke(StreamTask.java:639)
	at org.apache.flink.streaming.runtime.tasks.StreamTask.runWithCleanUpOnFail(StreamTask.java:650)
	at org.apache.flink.streaming.runtime.tasks.StreamTask.invoke(StreamTask.java:623)
	at org.apache.flink.runtime.taskmanager.Task.doRun(Task.java:779)
	at org.apache.flink.runtime.taskmanager.Task.run(Task.java:566)
	at java.lang.Thread.run(Thread.java:748)
22/04/21 10:49:30 INFO akka.AkkaRpcService: Stopping Akka RPC service.

タイムゾーンを下流のテーブルに追加できますか?

4. 上流のテーブルにはタイムゾーンがなく、下流のテーブルにはタイムゾーンがあります

ダウンストリーム テーブル: mysql の日時とタイムスタンプ、元の対応する TIMESTAMP から TIMESTAMP_LTZ に変更
LTZ: LOCAL TIME ZONE の意味

mysql テーブル構造:

ここに画像の説明を挿入

mysql表:

        String createSql = "CREATE TABLE stock_basic_source(\n" +
                "  `i`  INT NOT NULL,\n" +
                "  `ts_code`     CHAR(10) NOT NULL,\n" +
                "  `symbol`   CHAR(10) NOT NULL,\n" +
                "  `name` char(10) NOT NULL,\n" +
                "  `area`   CHAR(20) NOT NULL,\n" +
                "  `industry`   CHAR(20) NOT NULL,\n" +
                "  `list_date`   CHAR(10) NOT NULL,\n" +
                "  `actural_controller`   CHAR(100),\n" +
                "  `update_time`   TIMESTAMP\n," +
                "  `update_timestamp`   TIMESTAMP\n," +
                "    PRIMARY KEY(i) NOT ENFORCED\n" +
                ") WITH (\n" +
                "  'connector' = 'mysql-cdc',\n" +
                "  'hostname' = 'hadoop103',\n" +
                "  'port' = '3306',\n" +
                "  'username' = 'XX',\n" +
                "  'password' = 'XX" +
                "  'database-name' = 'xxzh_stock',\n" +
                "  'table-name' = 'stock_basic2'\n" +
                ")" ;

下流のテーブル:

        String createSQl = "CREATE TABLE if not exists stock_basic2_iceberg_sink(\n" +
                "  `i`  INT NOT NULL,\n" +
                "  `ts_code`    CHAR(10) NOT NULL,\n" +
                "  `symbol`   CHAR(10) NOT NULL,\n" +
                "  `name` char(10) NOT NULL,\n" +
                "  `area`   CHAR(20) NOT NULL,\n" +
                "  `industry`   CHAR(20) NOT NULL,\n" +
                "  `list_date`   CHAR(10) NOT NULL,\n" +
                "  `actural_controller`   CHAR(100) ,\n" +
                "  `update_time`   TIMESTAMP_LTZ\n," +
                "  `update_timestamp`   TIMESTAMP_LTZ\n," +
                "   PRIMARY KEY(i) NOT ENFORCED\n" +
                ") with(\n" +
                " 'write.metadata.delete-after-commit.enabled'='true',\n" +
                " 'write.metadata.previous-versions-max'='5',\n" +
                " 'format-version'='2'\n" +
                ")";

テストの結果、問題ないことがわかりました。
spark-sql のクエリ結果:
ここに画像の説明を挿入
flink-sql クエリの結果:
ここに画像の説明を挿入

結論は

日付に関する質問: ソース テーブルにはタイムゾーンがなく、ダウンストリーム テーブルにはローカル タイムゾーンを設定する必要があります

おすすめ

転載: blog.csdn.net/spark_dev/article/details/124302929