因为在一篇博文上看到介绍“汽车之家介绍flink数据平台”中提到“基于 SQL 的开发流程”。基于kafka connector,通过source,sink,transformation三条sql完成数据接入,逻辑转换处理,结果落地三步工作。出于兴趣,自己去简(粗)单(糙)实现了这其中的一个小功能。相关的博文在这里,相关的代码上传到github

简单说,通过kafka connector用3条sql实现如图所示功能:

但是实现的过程中也遇到了两个问题。

问题

  • 截止到目前最新的flink版本在kafka connector也只支持 inStreamingMode,并不支持inBatchMode。不能实现汽车之家通过kafka connector来实现每日的定时统计。

https://nightlies.apache.org/flink/flink-docs-release-1.14/docs/connectors/table/kafka/

如图,只支持unbounded无界数据流,不支持bounded有界数据即batchmode.

  • 在sink的时候是只支持append模式,而在append模式下,不支持group by,因为使用了group by 会改行结果行。

    那么按照汽车之家每日统计PV,UV的需求必然需要使用到group by.按目前flink的最新版本也是办不到的。

    如果强行使用group by 将会抛出异常:

    目前sink只支持append模式,如果使用了group by 等会改变结果行,会报错:AppendStreamTableSink doesn't support consuming update changes which is produced by node GroupAggregate

对于spark和flink这种绝对主流的大数据框架,稍微上点规模的公司应该都有维护自己的内部分支,基于自家的业务做一些定制化开发。汽车之家应该也不例外。

所以以上功能flink社区版不能做到,汽车之家应该是基于内部的实现。

以上是背景介绍。

基于该功能并不算特别复杂,花了两天业余时间实现了。

思路

  • kafka参数问题

    要接入kafka,就要设置kafka连接信息,起始信息,以及结束信息.

    开始信息可选参数如下:

    参数名 参数值
    scan.startup.mode 可选值:'earliest-offset', 'latest-offset', 'group-offsets', 'timestamp' and 'specific-offsets'
    scan.startup.specific-offsets 指定每个分区的偏移量,比如:'partition:0,offset:42;partition:1,offset:300'
    scan.startup.timestamp-millis 直接指定开始时间戳,long类型

    依葫芦画瓢,去除earliest-offset,结束信息可选参数可设置成:

    参数名 参数值
    scan.endup.mode 可选值:'latest-offset', 'group-offsets', 'timestamp' and 'specific-offsets'
    scan.endup.specific-offsets 指定每个分区的偏移量,比如:'partition:0,offset:42;partition:1,offset:300'
    scan.sendup.timestamp-millis 直接指定结束时间戳,long类型
  • 支持batchmode的问题

    这里涉及到一个版本的问题。flink kafka connector API在最近几个版本变化挺大的。就内部实现而言,1.13和1.14也有不小的变化。

    比如,判断当前任务是否有界时,1.13版本是直接写为false



    而在1.14版本变成了可动态判断并设置

    public boolean isBounded() { return kafkaSource.getBoundedness() == Boundedness.BOUNDED; }

    可以看到这里通过kafkaSource.getBoundedness()获取当前任务是否有界,点进KafkaSource,对于boundedness属性,既然有getter那必然有setter啊。

    果不其然,在KafkaSourceBuilder类中提供了setBounded方法。

    这里还有意外惊喜,这个方法不但提供了设置bounded的功能,还能直接设置结束的参数。那么上一个kafka参数问题解决了定义问题,而在这里就解决了设置的问题。

  • 参数提交至kafkasource的问题

    参数问题分为定义提交。定义在第1部份已经解决,提交就是第2部份的setBounded,但在哪里触发呢?

    KafkaDynamicSource.createKafkaSource的方法里。这里可仿照switch(startupMode)写一个switch(endupuMode),在里面的分支去实现各种参数情况LATEST,TIMESTAMP,再在各个分支里设置kafka参数。

    在case分支我们可以仿照kafkaSourceBuilder.setStartingOffsets实现一个kafkaSourceBuilder.setEndOffsets。在flink 1.13就得这么实现。但在flink 1.14,经过前面的分析得知setBounded可设置结束参数。一举两得。

  • group by支持问题

    经过分析,我发现这个问题属于是庸人自扰。

    AppendStreamTableSink doesn't support group by仅在streamingmode模式下,batchmode不存在改变结果行的问题,所以,只要改成了batchmode,天然的就不存在group by 异常问题。

实现

选定flink 1.14版本,fork,拉取到本地,新建分支。

目前scan.endup.mode 只支持latest-offsettimestamp两种方式。

编译

代码实现完毕,本地编译。

使用maven,常规操作。有两个注意的点:

  • flink使用了spotless进行代码格式化检测。修改了源码重新编译如果代码格式不对,可能就是没换行或者少了多了一个空格,就通过不了。

    编译前,可以使用'mvn spotless:apply自动校正。

  • flink 使用了Checkstyle,一些代码使用了import static,添加静态引入后进行编译时要注意。

测试

编译成功后,可部署成单点或者伪集群模式测试。

这里采用本地测试。

  • flink-connector-kafka_2.11-1.14.0.jarflink-connector-kafka_2.11-1.14.0.xmlpom文件手动放入或者mvn install本地仓库。
  • 我测试的时候,需手动引用kafka-clients依赖。这点我不保证。

确保将重新编译后的jar包引入项目

测试代码:

{
EnvironmentSettings fsSettings = EnvironmentSettings.newInstance()
.inBatchMode()
// .inStreamingMode()
.build(); TableEnvironment te = TableEnvironment.create(fsSettings); String kafkaSql = "CREATE TABLE kafkatable (\n" +
" key STRING," +
" ts TIMESTAMP" +
") WITH (\n" +
" 'connector' = 'kafka',\n" +
" 'topic' = 'xxx',\n" +
" 'properties.bootstrap.servers' = 'xxx.xx.xxx.xxx:9092',\n" +
" 'properties.group.id' = 'xxx',\n" +
// -- optional: valid modes are "earliest-offset",
// -- "latest-offset", "group-offsets",
// -- or "specific-offsets"
" 'scan.startup.mode' = 'earliest-offset',\n" +
" 'scan.endup.mode' = 'latest-offset',\n" +
// " 'scan.endup.mode' = 'timestamp',\n" +
// " 'scan.endup.timestamp-millis' = '1641974234163',\n" +
// " 'scan.endup.mode' = 'latest-offset',\n" +
// "'scan.startup.specific-offsets' = 'partition:0,offset:20'," +
// " 'connector.specific-offsets.0.partition' = '0',"+
// "'connector.specific-offsets.0.offset' = '1',"+
" 'format' = 'json',\n" +
" 'json.fail-on-missing-field' = 'false',\n" +
" 'json.ignore-parse-errors' = 'true'\n" +
")";
te.executeSql(kafkaSql); String sqlFile = "CREATE TABLE fs_table (\n" +
" dt VARCHAR,\n" +
" pv BIGINT,\n" +
" uv BIGINT" +
") WITH (\n" +
" 'connector'='filesystem',\n" +
" 'path'='d://path',\n" +
" 'format'='json',\n" +
" 'sink.partition-commit.delay'='1 s',\n" +
" 'sink.partition-commit.policy.kind'='success-file'\n" +
")";
te.executeSql(sqlFile); te.executeSql("INSERT INTO fs_table\n" +
"SELECT\n" +
" 'as' as dt,\n" +
" COUNT(*) AS pv,\n" +
" COUNT(DISTINCT key) AS uv\n" +
"FROM kafkatable group by key\n").print();
}

测试代码的sql逻辑仅为测试。不要追究为什么count(*)是pv,随手写的。

测试代码scan.endup.mode设置为latest-offset。如果要实现最开始的按天统计,如下设置。scan.startup.mode同理。

"  'scan.endup.mode' = 'timestamp',\n" +
" 'scan.endup.timestamp-millis' = '1641974234163',\n" +

这段代码测试通过inBatchMode引入kafka数据源,并将处理后的数据写入本地文件。

运行结果,测试通过。

《Flink SQL任务自动生成与提交》后续:修改flink源码实现kafka connector BatchMode的更多相关文章

  1. Flink SQL任务自动生成与提交

    目录 起因 思路 实现 1.配置 2.界面如下 3.环境 问题 起因 事情的起因,是看到一篇公众号文章Apache Flink 在汽车之家的应用与实践,里面提到了"基于 SQL 的开发流程& ...

  2. Excel 数据导入SQL XML 自动生成表头

    去出差的时候应客户要求要要将Excel 文件内的数据批量导入到数据库中,而且有各种不同种类的表格,如果每一个表格多对应一个数据表的话, 按照正常的方法应该是创建数据表,创建数据库中映射的数据模型,然后 ...

  3. Entity Framewrok 7beta7中不同版本sql server自动生成分页sql语句的问题

    在EF中,使用linq进行分页是很方便的,假如我们有一个EMP表,结构如下: public class Emp { [Key] public Guid No { get; set; } public ...

  4. Springboot+Redisson自定义注解一次解决重复提交问题(含源码)

    前言   项目中经常会出现重复提交的问题,而接口幂等性也一直以来是做任何项目都要关注的疑难点,网上可以查到非常多的方案,我归纳了几点如下:   1).数据库层面,对责任字段设置唯一索引,这是最直接有效 ...

  5. 学习 opencv---(6)玩转opencv源代码:生成opencv 工程解决方案与opencv 源码编译

    在这篇中,我们探讨如何通过已安装的opencv选择不同的编译器类型,生成高度还原的OpenCV开发时的解决方案工程文件,欣赏OpenCV新版本中总计 六十六多万行的精妙源代码.我们可以对其源代码进行再 ...

  6. Android 二维码 生成和识别(附Demo源码)

    今天讲一下目前移动领域很常用的技术——二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS. Android.WP都有相关支持的软件.之前我就想了解二维码是如何工作,最近因为工作需要使用相关技 ...

  7. 【转】Android 二维码 生成和识别(附Demo源码)--不错

    原文网址:http://www.cnblogs.com/mythou/p/3280023.html 今天讲一下目前移动领域很常用的技术——二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS. ...

  8. 【转载】Redis 4.0 自动内存碎片整理(Active Defrag)源码分析

    click原文链接原文链接:https://blog.csdn.net/zouhuajianclever/article/details/90669409阅读本文前建议先阅读此篇博客: Redis源码 ...

  9. Spring Framework自动装配setAutowireMode和Mybatis案例的源码探究

    由前文可得知, Spring Framework的自动装配有两种方式:xml配置和注解配置: 自动装配的类型有: (1)xml配置中的byType根据类型查找(@Autowired注解是默认根据类型查 ...

随机推荐

  1. CF638A Home Numbers 题解

    Content Vasya 的家在一条大街上,大街上一共有 \(n\) 座房子,其中,奇数编号的房子在大街的一侧,从左往右依次编号为 \(1,3,5,7,...,n-1\),偶数编号的房子在大街的另一 ...

  2. 不同机房vpc使用openswan打通内网

    1.测试环境: 北京6云主机:120.92.51.75/10.0.3.13     VPC:10.0.0.0/16 Ren-test 上海2云主机:42.157.163.120/192.168.3.3 ...

  3. 【LeetCode】773. Sliding Puzzle 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/sliding- ...

  4. 【LeetCode】621. Task Scheduler 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 公式法 日期 题目地址:https://leetco ...

  5. 应用程序开发 WebApp NativeApp 微信小程序

    Web    Native App  微信小程序 WebApp是指基于Web的系统和应用,其作用是向广大的最终用户发布一组复杂的内容和功能.webapp 框架是一种简单的与WSGI兼容的网络应用程序框 ...

  6. HDFS源码解析:教你用HDFS客户端写数据

    摘要:终于开始了这个很感兴趣但是一直觉得困难重重的源码解析工作,也算是一个好的开端. 本文分享自华为云社区<hdfs源码解析之客户端写数据>,作者: dayu_dls. 在我们客户端写数据 ...

  7. Deepin20系统安装Nvidia驱动

    Deepin20系统安装Nvidia驱动 系统设备配置信息如下: 电脑型号:华硕天选air[ASUS-FX516P] 显卡型号:RTX 3070 移动版独显 处理器型号: 11th Gen Intel ...

  8. 中华古诗词知识图谱之实体关系构建&导入neo4j数据库

    实体分析 诗名实体 属性 包含:作诗时间,诗名,内容,翻译,背景. 关系 实体1 关系 实体2 诗名 形式 诗词形式 诗名 作者 诗人 诗名 分类 类别 诗名 词牌名 词牌名 诗名 曲牌名 曲牌名 诗 ...

  9. JS事件冒泡与事件捕获怎么理解?

    在js中存在事件冒泡与事件捕获两种概念,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题. 事件冒泡(dubbed bubbling) 事件冒泡我们从字面意思理解就是当用户行为触发我们页面的定 ...

  10. Java面向对象笔记 • 【第5章 异常处理】

    全部章节   >>>> 本章目录 5.1 异常概述 5.1.1 程序中的异常 5.1.2 异常分类 5.1.3 实践练习 5.2 try-catch处理异常 5.2.2 使用f ...