之前做过数据平台,对于实时数据采集,使用了Flink。现在想想,在数据开发平台中,Flink的身影几乎无处不在,由于之前是边用边学,总体有点混乱,借此空隙,整理一下Flink的内容,算是一个知识积累,同时也分享给大家。
注意:由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是 Flink-1.19.x,Flink支持多种语言,这里的所有代码都是使用java,JDK版本使用的是19。
代码参考:https://github.com/forever1986/flink-study.git
目录
上一章对FlinkSQL基本入门及其其中的原理进行了讲解。这一章先从FlinkSQL的基础开始讲起,为了是那些没有什么标准SQL基础的朋友,如果你有基础,直接可以跳过第一部分。第二部分按照前面Data Stream API的顺序,开始讲解在sql-client中如何设置执行环境。不记得的话可以回顾一下《系列之五 - Data Stream API的执行环境》中的内容。最后一部分讲解一下sql-client工具的显示模式,只是为了后续演示或者开发过程中的方便。
1 建库建表操作
如果学过标准SQL语法的朋友,那么这一部分可以不用看或者快速过一遍。其语法与标准SQL 相差不大,主要的部分细微差别。
1.1 建库操作
熟悉关系型数据库的朋友可能知道,有些关系型数据库比如oracle就分3层:命名空间(schema)–数据库(database)–表(table)。在FlinkSQL中同样也分三层。目录(catalog)–数据库(database)–表(table)。关于目录(catalog)部分,它与关联实际数据库相关,后续再讲解,这里只需要知道有一个默认的default_catalog即可。
1)查看数据库
show databases;
show current database;
2)建立数据库
# 语法
CREATE DATABASE [IF NOT EXISTS] [catalog_name.]db_name
[COMMENT database_comment]
WITH (key1=val1, key2=val2, ...)
# 测试示例
create database test;
3)删除数据库
# 语法
DROP DATABASE [IF EXISTS] [catalog_name.]db_name [ (RESTRICT | CASCADE) ]
# 测试示例
drop database if exists test;
注意:删除数据库可以加上关键字RESTRICT表示如果库里面有表,则不允许删除(这是默认的)。如果加上关键字CASCADE则会删除库里面的所有表和函数。
更详细的语法,可以参考《官方文档》
1.2 建表操作
1.2.1 基本语法
创建表的语句语法与关系型数据库的SQL基本一致,只不过增加一些Connector的语法(也就是WITH部分)
CREATE TABLE [IF NOT EXISTS] [catalog_name.][db_name.]table_name
(
{ <physical_column_definition> | <metadata_column_definition> | <computed_column_definition> }[ , ...n]
[ <watermark_definition> ]
[ <table_constraint> ][ , ...n]
)
[COMMENT table_comment]
[PARTITIONED BY (partition_column_name1, partition_column_name2, ...)]
WITH (key1=val1, key2=val2, ...)
[ LIKE source_table [( <like_options> )] | AS select_query ]
说明:
- 1)IF NOT EXISTS:加上表示不存在则创建,存在则不创建。这样如果表已存储,则不会报错。
- 2)[catalog_name.][db_name.]table_name : 目录名+数据库名+表名。其中 目录名+数据库名可以不填写,则默认当前目录和数据库。
- 3)physical_column_definition:列名定义,physical_column_definition是定义常规的列。语法如下:
column_name column_type [ <column_constraint> ] [COMMENT column_comment]
# 其中<column_constraint> 的语法如下:
[CONSTRAINT constraint_name] PRIMARY KEY NOT ENFORCED
# PRIMARY KEY 表示唯一主键,NOT ENFORCED是表示不强制
- 4)metadata_column_definition:列名定义,metadata_column_definition是定义来之Connector的元数据类,这个后面讲Connector时会讲。语法如下:
column_name column_type METADATA [ FROM metadata_key ] [ VIRTUAL ]
# 其中VIRTUAL 表示该列不持久化
- 5)computed_column_definition:列名定义,computed_column_definition为计算列,也就是可以定义一个通过简单计算得出来的列,比如在某一列基础上加上某个值。语法如下:
column_name AS computed_column_expression [COMMENT column_comment]
- 6)watermark_definition:水位线的定义,这部分与之前学习到《系列之十七 - 高级概念 - 事件时间和水位线》中水位线是一致的。语法如下:
WATERMARK FOR rowtime_column_name AS watermark_strategy_expression
- 7)table_constraint:语法如下:
[CONSTRAINT constraint_name] PRIMARY KEY (column_name, ...) NOT ENFORCED
- 8)PARTITIONED BY :用于创建分区。语法如下:
PARTITIONED BY (partition_column_name1, partition_column_name2, ...)
- 9)WITH :连接器,前面讲解Data Stream API的输入和输出算子中就讲到连接器,而SQL API也是可以定义这些连接器。下面是一个kafka的connector示例:
CREATE TABLE KafkaTable (
`user_id` BIGINT,
`item_id` BIGINT,
`behavior` STRING,
`ts` TIMESTAMP_LTZ(3) METADATA FROM 'timestamp'
) WITH (
'connector' = 'kafka',
'topic' = 'user_behavior',
'properties.bootstrap.servers' = 'localhost:9092',
'properties.group.id' = 'testGroup',
'scan.startup.mode' = 'earliest-offset',
'format' = 'csv'
)
- 10)LIKE:基于现有的表,创建新的表。语法如下:
LIKE source_table [( <like_options> )]
- 11)AS:基于查询语句,创建新的表。语法如下:
AS select_query
使用AS创建表,还有一些限制如下:
① 目前还不支持创建临时表。
② 尚不支持指定显式列。
③ 尚不支持指定显式水印。
④ 不支持创建分区表。
⑤ 尚不支持指定主键约束。
- 12)列的类型:Flink中定义的表的列的类型,可以参考《官方文档》
当然,这里面有很多细节在后面会详细的讲解,这里就先了解基本的创建语句。下面也通过简单的几个创建表的操作来加深一下印象。
1.2.2 示例演示
示例说明:这里通过创建一个基于print的输出表,然后插入数据,在控制台看看数据是否到print输出算子中
1)创建一个写入print输出算子的表
CREATE TABLE log(
id STRING,
cpu DOUBLE,
ts INT
) WITH (
'connector' = 'print'
);
2)查看刚才新建的log表
desc log;
这里说明一下表格的含义:name为列名,type为类型,null为是否可空,key为主键,extras为格外属性,watermark为水位线
3)使用like创建log_copy表
CREATE TABLE log_copy(memory DOUBLE) LIKE log;
4)查看log_copy表
desc log_copy;
5)往log表插入数据
insert into log values('server1',20.4,1);
注意:这里可以看到当插入数据时,会生成一个Job任务。可以同Web-UI的控制台看到该任务,以及在控制台输出日志:
输出日志如下:
如果你对log进行select的时候会报错,这是因为print这个的Connector只支持sink,因此sink可以插入,但是不能select。这一块后续关于源算子、输出算子相关的Connector时会讲到。
上面只是简单演示了SQL在Flink的sql-client客户端工具的使用,接下来讲解如何在sql-client中设置执行环境。在前面的Data Stream API中《系列之五 - Data Stream API的执行环境》会设置一些执行环境设置,如果不记得可以回顾一下这章。
2 执行环境
在Data Stream API中《系列之五 - Data Stream API的执行环境》会设置一些执行环境设置,那么在SQL API方式下,如何设置:
1)执行环境:在Data Stream API中可以设置流处理或者批处理,在SQL API设置如下:
SET execution.runtime-mode=streaming; # streaming是默认,如果批处理使用batch
2)并行度:设置默认并行度
SET parallelism.defaut=1;
3)状态TTL:设置状态的过期时间,这个很重要,在SQL API中,很多操作其实都会存储状态,需要根据业务定时清理,不然会导致内存溢出。
SET parallelism.defaut=1;
4)显示模式:这是是执行结果的查询,特别是select语句,由于Flink的数据是流,因此select结果其实一个是连续查询的动态表,因此需要客户端可以刷新查看结果。在Flink中提供三种模式,这个在下一部分独立讲解
SET sql-clent.execution.result-mode=TABLE; # 支持TABLE(默认)、CHANGELOG、TABLEAU
其它参数可以参考《官方文档中Configuration》
3 显示模式
在使用SQL API过程中,经常会先通过select语句测试一下要执行的步骤是否正确,这对研发过程非常重要。sql-client客户端工具提供3种select可视化的显示模式。在此之前,先准备一下工作,下面SQL脚本相当于创建一个来之自动生成数字的源算子:
CREATE TABLE log(
id INT,
cpu DOUBLE,
ts INT
) WITH (
'connector' = 'datagen',
'rows-per-second'='1',
'fields.id.kind'='random',
'fields.id.min'='1',
'fields.id.max'='5',
'fields.cpu.kind'='random',
'fields.cpu.min'='1',
'fields.cpu.max'='100',
'fields.ts.kind'='sequence',
'fields.ts.start'='1',
'fields.ts.end'='100000'
);
3.1 TABLE显示模式
这个是是默认模式,不需要设置:
select * from log;
结果如下:
从上面的图可以看到。和关系型数据库的客户端工具基本上一致,就是一张表,会不断刷新,可以翻页等功能
3.2 CHANGELOG显示模式
SET sql-client.execution.result-mode=CHANGELOG;
select * from log;
从上面的图可以看到。这边多了一个OP的字段,这是一个显示追加的标志,+I表示插入,-U表示回撤,+U表示更新
3.3 TABLEAU显示模式
SET sql-client.execution.result-mode=TABLEAU;
select * from log;
从上面的图可以看到。界面不会跳到另外一个页面,其显示基本跟CHANGELOG模式一样
结语:本章通过基础的建库建表、执行环境配置以及显示模式演示,这些都是为了后面做基础,接下来就按照Data Stream API 方式来讲解在SQL API中如何实现对应功能。