Flink集成数据湖之实时数据写入iceberg
背景
随着大数据处理结果的实时性要求越来越高,越来越多的大数据处理从离线转到了实时,其中以flink为主的实时计算在大数据处理中占有重要地位。
Flink消费kafka等实时数据流。然后实时写入hive,在大数据处理方面有着广泛的应用。此外由于列式存储格式如parquet或者orc在查询性能方面有着显著的提高,所以大家都会优先选择列式存储作为我们的存储格式。
传统的这种架构看似不错,但是还是有很多没有解决的问题:
- 实时写入造成大量小文件,需要单独的程序来进行合并
- 实时的写入,读取,还有合并小文件在同时进行,那么如何保证事务,读取数据的时候不会出现脏读。
- Hdfs的数据一般是一次写入。多次读写,但是如果因为程序出错导致数据错了,确实要修改某一条数据改怎么办
- 消费kafka的数据落地到hive,有一天kafka的数据多了几个字段,如何同步到hive?必须删了重建吗?
- 订单等业务数据一般存储在传统数据库,如mysql等。如何实时同步这些cdc数据到hive仓库呢,包括ddl和dml
如果你有上面的需求,那么你可以考虑一下数据湖了,目前开源的数据湖技术主要有以下几个:delta、hudi、iceberg,但是侧重点有所不同,我上面说的问题也不完全都能实现,但是这些都是数据湖要做的东西,随着社区的不断发展,这些功能都会有的。
但是目前世面上这些数据湖技术都与spark紧密绑定。而我们目前实时计算主要以flink为主,而且我个人觉得未来实时计算也将以flink为主,所以我选择了iceberg为我们的数据湖,虽然他有一些功能不是很完善,但是有着良好的抽象,并且不强制绑定spark,所以对于iceberg没有的功能,我们可以自己给补全,再回馈给社区,一起成长。
iceberg简介
其实对于iceberg,官方的定义是一种表格式。
Apache Iceberg is an open table format for huge analytic datasets. Iceberg adds tables to Presto and Spark that use a high-performance format that works just like a SQL table.
我们可以简单理解为他是基于计算层(flink , spark)和存储层(orc,parqurt)的一个中间层,我们在hive建立一个iceberg格式的表。用flink或者spark写入iceberg,然后再通过其他方式来读取这个表,比如spark,flink,presto等。
当然数据湖的概念远不止这点,我们今天就先简单的这么理解,后续写一篇文章专门介绍一下iceberg。
flink实时写入
准备sql client环境
目前官方的测试版本是基于scala 2.12版本的flink。所以我们也用和官方同步的版本来测试下,下载下面的两个jar放到flink的lib下面,然后启动一下flink集群,standalone模式。
- 下载flink :flink-1.11.2-bin-scala_2.12.tgz
- 下载 iceberg-flink-runtime-xxx.jar
- 下载flink 集成hive的connector,flink-sql-connector-hive-2.3.6_2.12-1.11.2.jar
- 目前官方的hive测试版本是 2.3.7,其他的版本可能有不兼容
注意要配置flink的checkpoint,因为目前flink提交iceberg的信息是在每次checkpoint的时候提交的。在sql client配置checkpoint的方法如下:
在flink-conf.yaml添加如下配置
execution.checkpointing.interval: 10s # checkpoint间隔时间
execution.checkpointing.tolerable-failed-checkpoints: 10 # checkpoint 失败容忍次数
创建catalog
目前系统提供的catalog有hivecatalog和hadoopcatalog以及自定义catlog
CREATE CATALOG iceberg WITH (
'type'='iceberg',
'catalog-type'='hive',
'uri'='thrift://localhost:9083',
'clients'='5',
'property-version'='1',
'warehouse'='hdfs://nn:8020/warehouse/path'
);
执行完之后,显示如下:
Flink SQL> show catalogs;
default_catalog
iceberg
如果不想每次启动sql client都重新执行ddl,可以在sql-client-defaults.yaml
里面皮遏制一下:
catalogs: # empty list
# A typical catalog definition looks like:
- name: hive
type: hive
hive-conf-dir: /Users/user/work/hive/conf
default-database: default
- name: iceberg
type: iceberg
warehouse: hdfs://localhost/user/hive2/warehouse
uri: thrift://localhost:9083
catalog-type: hive
创建db
use catalog iceberg;
CREATE DATABASE iceberg_db;
USE iceberg_db;
创建table
CREATE TABLE iceberg.iceberg_db.iceberg_001 (
id BIGINT COMMENT 'unique id',
data STRING
) WITH ('connector'='iceberg','write.format.default'='ORC');
插入数据
我们依然创建一个datagen的connector。
CREATE TABLE sourceTable (
userid int,
f_random_str STRING
) WITH (
'connector' = 'datagen',
'rows-per-second'='100',
'fields.userid.kind'='random',
'fields.userid.min'='1',
'fields.userid.max'='100',
'fields.f_random_str.length'='10'
)
这时候我们看到有两个表了
Flink SQL> show tables;
iceberg_001
sourcetable
然后执行insert into插入数据:
insert into iceberg.iceberg_db.iceberg_001 select * from iceberg.iceberg_db.sourceTable
查询
我们这里使用presto来查询
presto的配置iceberg.properties 如下:
connector.name=iceberg
hive.metastore.uri=thrift://localhost:9083
代码版本
public class Flink2Iceberg{
public static void main(String[] args) throws Exception{
StreamExecutionEnvironment env =
StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
env.enableCheckpointing(10000);
StreamTableEnvironment tenv = StreamTableEnvironment.create(env);
tenv.executeSql("CREATE CATALOG iceberg WITH (n" +
" 'type'='iceberg',n" +
" 'catalog-type'='hive'," +
" 'hive-conf-dir'='/Users/user/work/hive/conf/'" +
")");
tenv.useCatalog("iceberg");
tenv.executeSql("CREATE DATABASE iceberg_db");
tenv.useDatabase("iceberg_db");
tenv.executeSql("CREATE TABLE sourceTable (n" +
" userid int,n" +
" f_random_str STRINGn" +
") WITH (n" +
" 'connector' = 'datagen',n" +
" 'rows-per-second'='100',n" +
" 'fields.userid.kind'='random',n" +
" 'fields.userid.min'='1',n" +
" 'fields.userid.max'='100',n" +
"'fields.f_random_str.length'='10'n" +
")");
tenv.executeSql(
"insert into iceberg.iceberg_db.iceberg_001 select * from iceberg.iceberg_db.sourceTable");
}
}
具体见:
总结
总结一下,iceberg的资料比较少,很多设计或者讨论等需要关注issues,然后再去撸源码,可能对于刚入门的小伙伴来说有点困难。后续我也会多分享一些关于iceberg的文章,欢迎大家关注我公众号【大数据技术与应用实战】。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Spring Security 中的 hasRole 和 hasAuthority 有区别吗?
- python常见的import导包技巧
- 真正了解贪心算法,这是一篇精华入门总结...
- MGR修改max_binlog_cache_size参数导致异常
- 【技术创作101训练营】TensorFlow Lite的 GPU 委托(Delegate)加速模型推理
- 弄懂这 5 个问题,拿下 Python 迭代器!
- 1500字,8个问题,彻底理解堆!
- Python画王者荣耀英雄能力雷达图
- Python语言的精华:Itertools库
- MySQL为什么lsof会看到这么多临时文件
- IE浏览器主页被劫持,如何解决主页被篡改问题?
- 参与国际化项目一定要遵循的java命名规范
- 威胁事件告警分析技巧及处置(二)
- 组复制安全 | 全方位认识 MySQL 8.0 Group Replication
- 那些年我们遇的bug