flink SQL 将msyql当做数据源
- 阿里耙耙开源的flink-mysql-conn-cdc:https://github.com/ververica/flink-cdc-connectors
- 原理:获取mysql增删改查所产生的日志信息binlog,将二进制binlog数据(StringDebeziumDeserializationSchema)反序列化转化成kafka-Debezium-JSON
- 代码示例:此程序为mysql Binlog日志的获取
package conn; import com.alibaba.ververica.cdc.connectors.mysql.MySQLSource; import com.alibaba.ververica.cdc.connectors.mysql.table.StartupOptions; import com.alibaba.ververica.cdc.debezium.DebeziumSourceFunction; import com.alibaba.ververica.cdc.debezium.StringDebeziumDeserializationSchema; import org.apache.flink.api.common.restartstrategy.RestartStrategies; import org.apache.flink.runtime.state.filesystem.FsStateBackend; import org.apache.flink.streaming.api.CheckpointingMode; import org.apache.flink.streaming.api.datastream.DataStreamSource; import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; import org.apache.flink.streaming.api.environment.CheckpointConfig; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import java.util.Properties; public class FlinkConnectorMysqlCDCDemo { private static Properties properties; public static void main(String[] args) throws Exception { //TODO 1.获取流处理执行环境 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.setParallelism(1); //1.1Checkpoint相关 /*读取的是binlog中的数据,如果集群挂掉,尽量能实现断点续传功能。如果从最新的读取(丢数据)。如果从最开始读(重复数据)。理想状态:读取binlog中的数据读一行,保存一次读取到的(读取到的行)位置信息。而flink中读取行位置信息保存在Checkpoint中。使用Checkpoint可以把flink中读取(按行)的位置信息保存在Checkpoint中*/ env.enableCheckpointing(5000L);//5s执行一次Checkpoint //设置Checkpoint的模式:精准一次 env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE); //任务挂掉的时候是否清理checkpoint。使任务正常退出时不删除CK内容,有助于任务恢复。默认的是取消的时候清空checkpoint中的数据。RETAIN_ON_CANCELLATION表示取消任务的时候,保存最后一次的checkpoint。便于任务的重启和恢复,正常情况下都使用RETAIN env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION); //设置一个重启策略:默认的固定延时重启次数,重启的次数是Integer的最大值,重启的间隔是1s env.setRestartStrategy(RestartStrategies.fixedDelayRestart(3, 2000L)); //设置一个状态后端 jobManager。如果使用的yarn集群模式,jobManager随着任务的生成而生成,任务挂了jobManager就没了。因此需要启动一个状态后端。只要设置checkpoint,尽量就设置一个状态后端。保存在各个节点都能读取的位置:hdfs中 // env.setStateBackend(new FsStateBackend("hdfs://hadoop102:8020/flink/ck/")); //指定用户 // System.setProperty("HADOOP_USER_NAME", "atguigu"); //TODO 2.读取mysql变化数据 监控MySQL中变化的数据 Properties properties = new Properties(); //创建一个变量可以添加之后想添加的配置信息 DebeziumSourceFunction<String> sourceFunction = MySQLSource.<String>builder() //使用builder创建MySQLsource对象,需要指定对象的泛型。 .hostname("127.0.0.1") //指定监控的哪台服务器(MySQL安装的位置) .port(3306) //MySQL连接的端口号 .username("root") //用户 .password("123456")//密码 .databaseList("xxxx") //list:可以监控多个库 .tableList("xxx.xxxx") //如果不写则监控库下的所有表,需要使用【库名.表名】 .serverId(9999) //.debeziumProperties(properties)//debezium中有很多配置信息。可以创建一个对象来接收 .deserializer(new StringDebeziumDeserializationSchema()) //读的数据是binlog文件,反序列化器,解析数据 .startupOptions(StartupOptions.initial()) //初始化数据:空值读不读数据库中的历史数据。initial(历史+连接之后的)、latest-offset(连接之后的)。timestamp(根据指定时间戳作为开始读取的位置) .build(); env .addSource(sourceFunction) .print().setParallelism(1); //TODO 4.启动任务 env.execute(); } }
-
mysql数据的获取:值得注意点是flink1.10后将tEnv.sqlUpdate抛弃,更换为executeSql(table_name),进行sql表的创建sqlQuery(table_name)为sql增删改的执行
package conn; import org.apache.flink.api.java.utils.ParameterTool; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.table.api.Table; import org.apache.flink.table.api.bridge.java.StreamTableEnvironment; import org.apache.flink.types.Row; public class source_mysql { public static void main(String[] args) throws Exception { final ParameterTool params = ParameterTool.fromArgs(args); final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.setParallelism(1); // source only supports parallelism of 1 final StreamTableEnvironment tEnv = StreamTableEnvironment.create(env); String SOURCE_MYSQL= "CREATE TABLE mysql_ssp_slot(\n"+ "id STRING,\n"+ "name STRING,\n"+ "name2 STRING,\n"+ "name3 STRING\n"+ ")WITH (\n"+ "'connector' = 'mysql-cdc',\n"+ "'hostname' = '127.0.0.1',\n"+ "'port' = '3306',\n"+ "'username' = 'root',\n"+ "'password' = '123456',\n"+ "'database-name' = 'xxx',\n"+ "'table-name' = 'xxxx',\n"+ "'debezium.snapshot.mode' = 'initial'\n"+ ")\n"; tEnv.executeSql(SOURCE_MYSQL); String selectSql = "SELECT * FROM mysql_ssp_slot "; final Table result = tEnv.sqlQuery(selectSql); tEnv.toRetractStream(result,Row.class).print(); env.execute(); } }
-
即将更新:source-mysql动态数据,sink到kafka/clickhosue/mysql,思路cdc结合jdbc
-
记录一点感悟:flinksql是将数据均读取到代码中创建的create表,所有的查询语句基于create表进行查询,最后要保证有输出源,当输出源存在的时候,将不需要env.execute()
异常处理
- Could not find a suitable table factory for 'org.apache.flink.table.factories.TableSinkFactory'
处理:代码的问题,一定要按照官网参照写:https://ci.apache.org/projects/flink/flink-docs-release-1.10/dev/table/connect.html#csv-format
一定是connector.type等等书写有误 - clussNotFunction:
1、pom文件flink版本和依赖版本是否相同
2、需要到idea->File->Project Structure->勾选需要的依赖包 - The server time zone value 'Öйú±ê׼ʱ¼ä' is unrec
mysql时区的问题1、查看时区:show VARIABLES like '%time_zone%';
2、更改时区为UTC或者+08:00(多出在win系统):set global time_zone = '+8:00'; - org.apache.flink.table.api.TableColumn.isGenerated()Z
- docker版mysql开启binlog权限
show variables like 'log_bin'; echo -e '[mysqld]\npid-file\t= /var/run/mysqld/mysqld.pid\nsocket\t= /var/run/mysqld/mysqld.sock\ndatadir\t= /var/lib/mysql\nsymbolic-links=0\nserver-id = 1\nlog-bin = binlog\nlog-bin-index = binlog.index'>mysqld.cnf