这是我毕业设计项目中的一个模块,后面会提供源码
这个模块做的是实时统计用户每10分钟内的搜索次数,也就是10分钟级别的搜索频率。用户搜索时,服务端会把搜索数据发送的Kafka中。
直接看Flink的部分吧,这部分做的事情就是消费Kafka中的数据然后基于Event Time(事件时间)
的10分钟级别的滚动窗口
统计搜索次数。然后将结果集sink到mysql中。这个功能实现起来还是比较简单的,再加上用FlinkSQL来做就更容易了。先看代码吧
CREATE TABLE KAFKA_SOURCE_SEARCH_DATA (
data VARCHAR,
ts timestamp(3),
WATERMARK FOR ts as ts - INTERVAL '5' SECOND
) WITH (
'connector.type' = 'kafka',
'connector.version' = 'universal',
'connector.properties.group.id' = 'group-flink',
'connector.topic' = 'search_data',
'connector.startup-mode' = 'earliest-offset',
'connector.properties.zookeeper.connect' = 'localhost:2181',
'connector.properties.bootstrap.servers' = 'kafka1:9094',
'format.type' = 'json'
)
CREATE TABLE MYSQL_SINK_SEARCH_FREQUENCY (
cnt BIGINT,
cnt_time timestamp(3)
) WITH (
'connector.type' = 'jdbc',
'connector.url' = 'jdbc:mysql://127.0.0.1:3306/search_lite?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&autoReconnect=true&failOverReadOnly=false',
'connector.table' = 'user_search_frequency',
'connector.username' = 'root',
'connector.password' = '',
'connector.write.flush.max-rows' = '1'
)
INSERT INTO MYSQL_SINK_SEARCH_FREQUENCY(cnt,cnt_time)
SELECT
COUNT(*) as cnt,
TUMBLE_START(ts, INTERVAL '10' MINUTE) as cnt_time
FROM KAFKA_SOURCE_SEARCH_DATA
GROUP BY TUMBLE(ts, INTERVAL '10' MINUTE)
{"data": "8-1受集度为q的均布载荷作用的矩形杠杆截面简支梁","ts": "2020-06-06T15:01:39.780Z"}
其实思路还是蛮清晰,先设计好源表和目标表,然后在设计计算逻辑。关于源表和目标表的创建以及FlinkSQL的使用,官网提供了详细的文档,这里就不再赘述了。
这里需要提的是关于时间的格式,时间格式要遵循Flink支持的格式,一开始我用的其他时间格式导致报了莫名其妙的错误。
private static final SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
嗯,其实写到这里,基本上就算完成了,可以直接使用Flink提供的sql-client提交就行了注意需要手动安装需要的依赖。但我这里使用的Java开发打包Jar提交的(后面再来写通过sql-client提交任务)。
使用官方提供的模板来创建项目,先看需要的依赖(部分代码)
<dependencies>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-table-api-java-bridge_2.11artifactId>
<version>${flink.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-table-api-javaartifactId>
<version>${flink.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-table-planner-blink_2.11artifactId>
<version>${flink.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-streaming-scala_2.11artifactId>
<version>${flink.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-table-commonartifactId>
<version>1.10.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-connector-kafka_2.11artifactId>
<version>${flink.version}version>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-jsonartifactId>
<version>${flink.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.19version>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-jdbc_2.11artifactId>
<version>${flink.version}version>
dependency>
...
dependencies>
这里注意前面的依赖是不需要在打包的时候打进去的。因为Flink自带这些。可在lib目录下看到。
如果数据源是Kafka的话,这里需要在build标签下加一行配置
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-shade-pluginartifactId>
<version>3.1.1version>
<executions>
<execution>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>xyh.SearchFrequencymainClass>
transformer>
transformers>
configuration>
execution>
executions>
plugin>
plugins>
build>
没有加这一行配置会导致打包的时候出问题(应该是依赖冲突,后面再研究),记得当时代码在本地跑完全没问题,打包提交的Flink上就报错了,卡了我很久,在网上找了很多资料,后来到stackoverflow上找到了解决的办法。
stackoverflow解决方案
依赖的问题解决好了之后,就可以在main方法中创建环境调用SQL代码就好了。
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
EnvironmentSettings settings = EnvironmentSettings.newInstance()
.useBlinkPlanner()
.inStreamingMode()
.build();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
StreamTableEnvironment tEnv = StreamTableEnvironment.create(env, settings);
//search frequency count
//---------------------------------------------------------------------------
//source
tEnv.sqlUpdate(ExecSQL.KAFKA_SOURCE_SEARCH_DATA);
//sink
tEnv.sqlUpdate(ExecSQL.MYSQL_SINK_SEARCH_FREQUENCY);
//operator
tEnv.sqlUpdate(ExecSQL.OPERATOR_FREQUENCY_COUNT);
tEnv.execute("SearchFrequency FlinkJob");
}
然后剩下的就是打包构建项目
mvn clean package
将jar包提交到Flink上
http://127.0.0.1:8081/#/submit
如果没问题的话,submit后是这样的
看一下MySQL中目标表中的结果(这里我为了方便测试,窗口时间改成了5秒)
下面的折线图,上面那个搜索词频统计后面再讲。
备注:毕业有段时间了,现在才想起整理这些东西,可能有些地方不详细或者有错误还望谅解。
参考资料
http://wuchong.me/blog/2020/02/25/demo-building-real-time-application-with-flink-sql/
http://wuchong.me/blog/2019/09/02/flink-sql-1-9-read-from-kafka-write-into-mysql/#more
https://www.bilibili.com/video/av90560012
https://hub.docker.com/_/flink?tab=description
https://ci.apache.org/projects/flink/flink-docs-release-1.10/zh/dev/connectors/kafka.html
https://www.jianshu.com/p/a0cc21243377
https://www.jianshu.com/p/5075154254ce
https://ci.apache.org/projects/flink/flink-docs-release-1.10/zh/dev/table/sql/create.html
https://ci.apache.org/projects/flink/flink-docs-release-1.10/zh/dev/table/sql/queries.html
https://blog.csdn.net/zhanghuolei/article/details/105767190
https://github.com/wuchong/flink-sql-demo/blob/master/pom.xml