Iceberg从入门到精通系列之十八:一篇文章深入了解Flink对Iceberg的支持
- 一、Flink支持的iceberg功能
- [二、使用Flink SQL Client时的准备](#二、使用Flink SQL Client时的准备)
- [三、Flink's Python API](#三、Flink's Python API)
- 四、添加目录。
- [五、Hive catalog](#五、Hive catalog)
- 六、类型转换
- 七、待支持的功能
Apache Iceberg 支持 Apache Flink 的 DataStream API 和 Table API。
一、Flink支持的iceberg功能
功能支持 | Flink | 注意事项 |
---|---|---|
SQL create catalog | ✔️ | |
SQL create database | ✔️ | |
SQL create table | ✔️ | |
SQL create table like | ✔️ | |
SQL alter table | ✔️ | 仅支持更改表属性,不支持列和分区更改 |
SQL drop_table | ✔️ | |
SQL select | ✔️ | 支持流式和批处理模式 |
SQL insert into | ✔️ | 支持流式和批处理模式 |
SQL insert overwrite | ✔️ | |
DataStream read | ✔️ | |
DataStream append | ✔️ | |
DataStream overwrite | ✔️ | |
Metadata tables | ✔️ | |
Rewrite files action | ✔️ |
二、使用Flink SQL Client时的准备
在 Flink 中创建 Iceberg 表,建议使用 Flink SQL Client,这样用户更容易理解概念。
从 Apache 下载页面下载 Flink。 Iceberg 在编译 Apache Iceberg-flink-runtime jar 时使用 Scala 2.12,因此建议使用与 Scala 2.12 捆绑在一起的 Flink 1.16。
bash
FLINK_VERSION=1.16.1
SCALA_VERSION=2.12
APACHE_FLINK_URL=https://archive.apache.org/dist/flink/
wget ${APACHE_FLINK_URL}/flink-${FLINK_VERSION}/flink-${FLINK_VERSION}-bin-scala_${SCALA_VERSION}.tgz
tar xzvf flink-${FLINK_VERSION}-bin-scala_${SCALA_VERSION}.tgz
在 Hadoop 环境中启动独立的 Flink 集群:
bash
# HADOOP_HOME is your hadoop root directory after unpack the binary package.
APACHE_HADOOP_URL=https://archive.apache.org/dist/hadoop/
HADOOP_VERSION=2.8.5
wget ${APACHE_HADOOP_URL}/common/hadoop-${HADOOP_VERSION}/hadoop-${HADOOP_VERSION}.tar.gz
tar xzvf hadoop-${HADOOP_VERSION}.tar.gz
HADOOP_HOME=`pwd`/hadoop-${HADOOP_VERSION}
export HADOOP_CLASSPATH=`$HADOOP_HOME/bin/hadoop classpath`
# Start the flink standalone cluster
./bin/start-cluster.sh
启动 Flink SQL 客户端。 Iceberg项目中有一个单独的flink-runtime模块来生成捆绑的jar,可以直接由Flink SQL客户端加载。要手动构建 flink-runtime 捆绑的 jar,请构建 Iceberg 项目,它将在 <iceberg-root-dir>/flink-runtime/build/libs 下生成 jar。或者从 Apache 存储库下载 flink-runtime jar。
bash
# HADOOP_HOME is your hadoop root directory after unpack the binary package.
export HADOOP_CLASSPATH=`$HADOOP_HOME/bin/hadoop classpath`
./bin/sql-client.sh embedded -j <flink-runtime-directory>/iceberg-flink-runtime-1.16-1.3.0.jar shell
默认情况下,Iceberg 附带用于 Hadoop 目录的 Hadoop jar。要使用 Hive 目录,请在打开 Flink SQL 客户端时加载 Hive jar。幸运的是,Flink 为 SQL 客户端提供了捆绑的 Hive jar。有关如何下载依赖项并开始使用的示例:
bash
# HADOOP_HOME is your hadoop root directory after unpack the binary package.
export HADOOP_CLASSPATH=`$HADOOP_HOME/bin/hadoop classpath`
ICEBERG_VERSION=1.3.0
MAVEN_URL=https://repo1.maven.org/maven2
ICEBERG_MAVEN_URL=${MAVEN_URL}/org/apache/iceberg
ICEBERG_PACKAGE=iceberg-flink-runtime
wget ${ICEBERG_MAVEN_URL}/${ICEBERG_PACKAGE}-${FLINK_VERSION_MAJOR}/${ICEBERG_VERSION}/${ICEBERG_PACKAGE}-${FLINK_VERSION_MAJOR}-${ICEBERG_VERSION}.jar -P lib/
HIVE_VERSION=2.3.9
SCALA_VERSION=2.12
FLINK_VERSION=1.16.1
FLINK_CONNECTOR_URL=${MAVEN_URL}/org/apache/flink
FLINK_CONNECTOR_PACKAGE=flink-sql-connector-hive
wget ${FLINK_CONNECTOR_URL}/${FLINK_CONNECTOR_PACKAGE}-${HIVE_VERSION}_${SCALA_VERSION}/${FLINK_VERSION}/${FLINK_CONNECTOR_PACKAGE}-${HIVE_VERSION}_${SCALA_VERSION}-${FLINK_VERSION}.jar
./bin/sql-client.sh embedded shell
三、Flink's Python API
使用 pip 安装 Apache Flink 依赖项:
bash
pip install apache-flink==1.16.1
提供iceberg-flink-runtime jar的file://路径,可以通过构建项目并查看/flink-runtime/build/libs获得,或者从Apache官方下载存储库。第三方 jar 可以通过以下方式添加到 pyflink:
- env.add_jars("文件:///my/jar/path/connector.jar")
- table_env.get_config().get_configuration().set_string("pipeline.jars", "file:///my/jar/path/connector.jar")
官方文档中也提到了这一点。下面的示例使用 env.add_jars(...):
python
import os
from pyflink.datastream import StreamExecutionEnvironment
env = StreamExecutionEnvironment.get_execution_environment()
iceberg_flink_runtime_jar = os.path.join(os.getcwd(), "iceberg-flink-runtime-1.16-1.3.0.jar")
env.add_jars("file://{}".format(iceberg_flink_runtime_jar))
接下来,创建StreamTableEnvironment并执行Flink SQL语句。以下示例展示了如何通过 Python Table API 创建自定义目录:
python
from pyflink.table import StreamTableEnvironment
table_env = StreamTableEnvironment.create(env)
table_env.execute_sql("""
CREATE CATALOG my_catalog WITH (
'type'='iceberg',
'catalog-impl'='com.my.custom.CatalogImpl',
'my-additional-catalog-config'='my-value'
)
""")
运行查询:
sql
(table_env
.sql_query("SELECT PULocationID, DOLocationID, passenger_count FROM my_catalog.nyc.taxis LIMIT 5")
.execute()
.print())
bash
+----+----------------------+----------------------+--------------------------------+
| op | PULocationID | DOLocationID | passenger_count |
+----+----------------------+----------------------+--------------------------------+
| +I | 249 | 48 | 1.0 |
| +I | 132 | 233 | 1.0 |
| +I | 164 | 107 | 1.0 |
| +I | 90 | 229 | 1.0 |
| +I | 137 | 249 | 1.0 |
+----+----------------------+----------------------+--------------------------------+
5 rows in set
四、添加目录。
Flink 支持使用 Flink SQL 创建目录。
目录配置
通过执行以下查询来创建和命名目录(将 <catalog_name> 替换为您的目录名称,将 <config_key>=<config_value> 替换为目录实现配置):
sql
CREATE CATALOG <catalog_name> WITH (
'type'='iceberg',
`<config_key>`=`<config_value>`
);
以下属性可以全局设置,并且不限于特定的目录实现:
- type:必须是iceberg。 (必需的)
- catalog-type:hive、hadoop 或rest 用于内置目录,或未设置以使用catalog-impl 实现自定义目录。 (选修的)
- Catalog-impl:自定义目录实现的完全限定类名。如果未设置目录类型,则必须设置。 (选修的)
- property-version:描述属性版本的版本号。如果属性格式发生更改,此属性可用于向后兼容。当前属性版本为1。(可选)
- cache-enabled:是否启用目录缓存,默认值为true。 (选修的)
- cache.expiration-interval-ms:目录条目在本地缓存多长时间,以毫秒为单位;负值如 -1 将禁用过期,值 0 不允许设置。默认值为-1。 (选修的)
五、Hive catalog
这将创建一个名为 hive_catalog 的 Iceberg 目录,可以使用 'catalog-type'='hive' 进行配置,该目录从 Hive 元存储加载表:
sql
CREATE CATALOG hive_catalog WITH (
'type'='iceberg',
'catalog-type'='hive',
'uri'='thrift://localhost:9083',
'clients'='5',
'property-version'='1',
'warehouse'='hdfs://nn:8020/warehouse/path'
);
如果使用 Hive 目录,可以设置以下属性:
- uri:Hive 元存储的 Thrift URI。 (必需的)
- client:Hive Metastore 客户端池大小,默认值为 2。(可选)
- warehouse:Hive仓库位置,如果既没有设置hive-conf-dir来指定包含hive-site.xml配置文件的位置,也没有在classpath中添加正确的hive-site.xml,则应指定此路径。
- hive-conf-dir:包含 hive-site.xml 配置文件的目录路径,该文件将用于提供自定义 Hive 配置值。如果同时设置 hive-conf-dir 和仓库,则 /hive-site.xml(或类路径中的 hive 配置文件)中的 hive.metastore.warehouse.dir 值将被仓库值覆盖创建iceberg目录。
- hadoop-conf-dir:包含 core-site.xml 和 hdfs-site.xml 配置文件的目录路径,这些文件将用于提供自定义 Hadoop 配置值。
创建表
sql
CREATE TABLE `hive_catalog`.`default`.`sample` (
id BIGINT COMMENT 'unique id',
data STRING
);
写数据
要将新数据附加到具有 Flink 流作业的表中,请使用 INSERT INTO:
sql
INSERT INTO `hive_catalog`.`default`.`sample` VALUES (1, 'a');
INSERT INTO `hive_catalog`.`default`.`sample` SELECT id, data from other_kafka_table;
要将表中的数据替换为查询结果,请在批处理作业中使用 INSERT OVERWRITE(flink 流作业不支持 INSERT OVERWRITE)。覆盖是 Iceberg 表的原子操作。
具有 SELECT 查询生成的行的分区将被替换,例如:
sql
INSERT OVERWRITE `hive_catalog`.`default`.`sample` VALUES (1, 'a');
Iceberg 还支持通过选择值覆盖给定分区:
sql
INSERT OVERWRITE `hive_catalog`.`default`.`sample` PARTITION(data='a') SELECT 6;
Flink 原生支持将 DataStream 和 DataStream 写入iceberg表。
java
StreamExecutionEnvironment env = ...;
DataStream<RowData> input = ... ;
Configuration hadoopConf = new Configuration();
TableLoader tableLoader = TableLoader.fromHadoopTable("hdfs://nn:8020/warehouse/path", hadoopConf);
FlinkSink.forRowData(input)
.tableLoader(tableLoader)
.append();
env.execute("Test Iceberg DataStream");
分支写入
FlinkSink 中的 toBranch API 还支持写入 Iceberg 表中的分支。
bash
FlinkSink.forRowData(input)
.tableLoader(tableLoader)
.toBranch("audit-branch")
.append();
读
使用以下语句提交 Flink 批处理作业:
sql
-- Execute the flink job in batch mode for current session context
SET execution.runtime-mode = batch;
SELECT * FROM `hive_catalog`.`default`.`sample`;
Iceberg 支持处理从历史快照 ID 开始的 Flink 流作业中的增量数据:
sql
-- Submit the flink job in streaming mode for current session.
SET execution.runtime-mode = streaming;
-- Enable this switch because streaming read SQL will provide few job options in flink SQL hint options.
SET table.dynamic-table-options.enabled=true;
-- Read all the records from the iceberg current snapshot, and then read incremental data starting from that snapshot.
SELECT * FROM `hive_catalog`.`default`.`sample` /*+ OPTIONS('streaming'='true', 'monitor-interval'='1s')*/ ;
-- Read all incremental data starting from the snapshot-id '3821550127947089987' (records from this snapshot will be excluded).
SELECT * FROM `hive_catalog`.`default`.`sample` /*+ OPTIONS('streaming'='true', 'monitor-interval'='1s', 'start-snapshot-id'='3821550127947089987')*/ ;
SQL 也是检查表的推荐方法。要查看表中的所有快照,请使用快照元数据表:
sql
SELECT * FROM `hive_catalog`.`default`.`sample`.`snapshots`
Iceberg支持Java API中的流式或批量读取:
java
DataStream<RowData> batch = FlinkSource.forRowData()
.env(env)
.tableLoader(tableLoader)
.streaming(false)
.build();
六、类型转换
Iceberg 对 Flink 的集成会自动在 Flink 和 Iceberg 类型之间进行转换。当写入 Flink 不支持的类型(例如 UUID)的表时,Iceberg 将接受并转换 Flink 类型的值。
Flink 到 Iceberg
Flink 类型按照下表转换为 Iceberg 类型:
Flink | Iceberg | Notes |
---|---|---|
boolean | boolean | |
tinyint | integer | |
smallint | integer | |
integer | integer | |
bigint | long | |
float | float | |
double | double | |
char | string | |
varchar | string | |
string | string | |
binary | binary | |
varbinary | fixed | |
decimal | decimal | |
date | date | |
time | time | |
timestamp | timestamp without timezone | |
timestamp_ltz | timestamp with timezone | |
array | list | |
map | map | |
multiset | map | |
row | struct | |
raw | Not supported | |
interval | Not supported | |
structured | Not supported | |
timestamp with zone | Not supported | |
distinct | Not supported | |
null | Not supported | |
symbol | Not supported | |
logical | Not supported |
Iceberg to Flink
Iceberg 类型按照下表转换为 Flink 类型:
Iceberg | Flink |
---|---|
boolean | boolean |
struct | row |
list | array |
map | map |
integer | integer |
long | bigint |
float | float |
double | double |
date | date |
time | time |
timestamp without timezone | timestamp(6) |
timestamp with timezone | timestamp_ltz(6) |
string | varchar(2147483647) |
uuid | binary(16) |
fixed(N) | binary(N) |
binary | varbinary(2147483647) |
decimal(P, S) | decimal(P, S) |
七、待支持的功能
目前的 Flink Iceberg 集成工作尚不支持一些功能:
- 不支持创建隐藏分区的Iceberg表
- 不支持创建带有计算列的Iceberg表
- 不支持创建带水印的Iceberg表
- 不支持添加列、删除列、重命名列、更改列,会在flink 1.18.0版本中支持