前言
在 《从0到1学习Flink》—— Data Source 介绍 文章中,我给大家介绍了 Flink Data Source 以及简短的介绍了一下自定义 Data Source,这篇文章更详细的介绍下,并写一个 demo 出来让大家理解。
Flink Kafka source
准备工作
我们先来看下 Flink 从 Kafka topic 中获取数据的 demo,首先你需要安装好了 FLink 和 Kafka 。
运行启动 Flink、Zookepeer、Kafka,
好了,都启动了!
maven 依赖
1<!--flink java-->
2<dependency>
3 <groupId>org.apache.flink</groupId>
4 <artifactId>flink-java</artifactId>
5 <version>${flink.version}</version>
6 <scope>provided</scope>
7</dependency>
8<dependency>
9 <groupId>org.apache.flink</groupId>
10 <artifactId>flink-streaming-java_${scala.binary.version}</artifactId>
11 <version>${flink.version}</version>
12 <scope>provided</scope>
13</dependency>
14<!--日志-->
15<dependency>
16 <groupId>org.slf4j</groupId>
17 <artifactId>slf4j-log4j12</artifactId>
18 <version>1.7.7</version>
19 <scope>runtime</scope>
20</dependency>
21<dependency>
22 <groupId>log4j</groupId>
23 <artifactId>log4j</artifactId>
24 <version>1.2.17</version>
25 <scope>runtime</scope>
26</dependency>
27<!--flink kafka connector-->
28<dependency>
29 <groupId>org.apache.flink</groupId>
30 <artifactId>flink-connector-kafka-0.11_${scala.binary.version}</artifactId>
31 <version>${flink.version}</version>
32</dependency>
33<!--alibaba fastjson-->
34<dependency>
35 <groupId>com.alibaba</groupId>
36 <artifactId>fastjson</artifactId>
37 <version>1.2.51</version>
38</dependency>
测试发送数据到 kafka topic
实体类,Metric.java
1package com.zhisheng.flink.model;
2
3import java.util.Map;
4
5/**
6 * Desc:
7 * weixi: zhisheng_tian
8 * blog: http://www.54tianzhisheng.cn/
9 */
10public class Metric {
11 public String name;
12 public long timestamp;
13 public Map<String, Object> fields;
14 public Map<String, String> tags;
15
16 public Metric() {
17 }
18
19 public Metric(String name, long timestamp, Map<String, Object> fields, Map<String, String> tags) {
20 this.name = name;
21 this.timestamp = timestamp;
22 this.fields = fields;
23 this.tags = tags;
24 }
25
26 @Override
27 public String toString() {
28 return "Metric{" +
29 "name='" + name + '\'' +
30 ", timestamp='" + timestamp + '\'' +
31 ", fields=" + fields +
32 ", tags=" + tags +
33 '}';
34 }
35
36 public String getName() {
37 return name;
38 }
39
40 public void setName(String name) {
41 this.name = name;
42 }
43
44 public long getTimestamp() {
45 return timestamp;
46 }
47
48 public void setTimestamp(long timestamp) {
49 this.timestamp = timestamp;
50 }
51
52 public Map<String, Object> getFields() {
53 return fields;
54 }
55
56 public void setFields(Map<String, Object> fields) {
57 this.fields = fields;
58 }
59
60 public Map<String, String> getTags() {
61 return tags;
62 }
63
64 public void setTags(Map<String, String> tags) {
65 this.tags = tags;
66 }
67}
往 kafka 中写数据工具类:KafkaUtils.java
1import com.alibaba.fastjson.JSON;
2import com.zhisheng.flink.model.Metric;
3import org.apache.kafka.clients.producer.KafkaProducer;
4import org.apache.kafka.clients.producer.ProducerRecord;
5
6import java.util.HashMap;
7import java.util.Map;
8import java.util.Properties;
9
10/**
11 * 往kafka中写数据
12 * 可以使用这个main函数进行测试一下
13 * weixin: zhisheng_tian
14 * blog: http://www.54tianzhisheng.cn/
15 */
16public class KafkaUtils {
17 public static final String broker_list = "localhost:9092";
18 public static final String topic = "metric"; // kafka topic,Flink 程序中需要和这个统一
19
20 public static void writetoKafka() throws InterruptedException {
21 Properties props = new Properties();
22 props.put("bootstrap.servers", broker_list);
23 props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); //key 序列化
24 props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); //value 序列化
25 KafkaProducer producer = new KafkaProducer<String, String>(props);
26
27 Metric metric = new Metric();
28 metric.setTimestamp(System.currentTimeMillis());
29 metric.setName("mem");
30 Map<String, String> tags = new HashMap<>();
31 Map<String, Object> fields = new HashMap<>();
32
33 tags.put("cluster", "zhisheng");
34 tags.put("host_ip", "101.147.022.106");
35
36 fields.put("used_percent", 90d);
37 fields.put("max", 27244873d);
38 fields.put("used", 17244873d);
39 fields.put("init", 27244873d);
40
41 metric.setTags(tags);
42 metric.setFields(fields);
43
44 ProducerRecord record = new ProducerRecord<String, String>(topic, null, null, JSON.toJSONString(metric));
45 producer.send(record);
46 System.out.println("发送数据: " + JSON.toJSONString(metric));
47
48 producer.flush();
49 }
50
51 public static void main(String[] args) throws InterruptedException {
52 while (true) {
53 Thread.sleep(300);
54 writetoKafka();
55 }
56 }
57}
运行:
如果出现如上图标记的,即代表能够不断的往 kafka 发送数据的。
Flink 程序
Main.java
1package com.zhisheng.flink;
2
3import org.apache.flink.api.common.serialization.SimpleStringSchema;
4import org.apache.flink.streaming.api.datastream.DataStreamSource;
5import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
6import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
7
8import java.util.Properties;
9
10/**
11 * Desc:
12 * weixi: zhisheng_tian
13 * blog: http://www.54tianzhisheng.cn/
14 */
15public class Main {
16 public static void main(String[] args) throws Exception {
17 final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
18
19 Properties props = new Properties();
20 props.put("bootstrap.servers", "localhost:9092");
21 props.put("zookeeper.connect", "localhost:2181");
22 props.put("group.id", "metric-group");
23 props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); //key 反序列化
24 props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
25 props.put("auto.offset.reset", "latest"); //value 反序列化
26
27 DataStreamSource<String> dataStreamSource = env.addSource(new FlinkKafkaConsumer011<>(
28 "metric", //kafka topic
29 new SimpleStringSchema(), // String 序列化
30 props)).setParallelism(1);
31
32 dataStreamSource.print(); //把从 kafka 读取到的数据打印在控制台
33
34 env.execute("Flink add data source");
35 }
36}
运行起来:
看到没程序,Flink 程序控制台能够源源不断的打印数据呢。
自定义 Source
上面就是 Flink 自带的 Kafka source,那么接下来就模仿着写一个从 MysqL 中读取数据的 Source。
1<dependency>
2 <groupId>MysqL</groupId>
3 <artifactId>mysql-connector-java</artifactId>
4 <version>5.1.34</version>
5</dependency>
数据库建表如下:
1DROP TABLE IF EXISTS `student`;
2CREATE TABLE `student` (
3 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
4 `name` varchar(25) COLLATE utf8_bin DEFAULT NULL,
5 `password` varchar(25) COLLATE utf8_bin DEFAULT NULL,
6 `age` int(10) DEFAULT NULL,
7 PRIMARY KEY (`id`)
8) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
插入数据:
1INSERT INTO `student` VALUES ('1', 'zhisheng01', '123456', '18'), ('2', 'zhisheng02', '123', '17'), ('3', 'zhisheng03', '1234', '18'), ('4', 'zhisheng04', '12345', '16');
2COMMIT;
新建实体类:Student.java
1package com.zhisheng.flink.model;
2
3/**
4 * Desc:
5 * weixi: zhisheng_tian
6 * blog: http://www.54tianzhisheng.cn/
7 */
8public class Student {
9 public int id;
10 public String name;
11 public String password;
12 public int age;
13
14 public Student() {
15 }
16
17 public Student(int id, String name, String password, int age) {
18 this.id = id;
19 this.name = name;
20 this.password = password;
21 this.age = age;
22 }
23
24 @Override
25 public String toString() {
26 return "Student{" +
27 "id=" + id +
28 ", name='" + name + '\'' +
29 ", password='" + password + '\'' +
30 ", age=" + age +
31 '}';
32 }
33
34 public int getId() {
35 return id;
36 }
37
38 public void setId(int id) {
39 this.id = id;
40 }
41
42 public String getName() {
43 return name;
44 }
45
46 public void setName(String name) {
47 this.name = name;
48 }
49
50 public String getpassword() {
51 return password;
52 }
53
54 public void setPassword(String password) {
55 this.password = password;
56 }
57
58 public int getAge() {
59 return age;
60 }
61
62 public void setAge(int age) {
63 this.age = age;
64 }
65}
新建 Source 类 SourceFromMysqL.java,该类继承 RichSourceFunction ,实现里面的 open、close、run、cancel 方法:
1 package com.zhisheng.flink.source;
2
3import com.zhisheng.flink.model.Student;
4import org.apache.flink.configuration.Configuration;
5import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
6
7import java.sql.Connection;
8import java.sql.DriverManager;
9import java.sql.PreparedStatement;
10import java.sql.ResultSet;
11
12
13/**
14 * Desc:
15 * weixi: zhisheng_tian
16 * blog: http://www.54tianzhisheng.cn/
17 */
18public class SourceFromMysqL extends RichSourceFunction<Student> {
19
20 PreparedStatement ps;
21 private Connection connection;
22
23 /**
24 * open() 方法中建立连接,这样不用每次 invoke 的时候都要建立连接和释放连接。
25 *
26 * @param parameters
27 * @throws Exception
28 */
29 @Override
30 public void open(Configuration parameters) throws Exception {
31 super.open(parameters);
32 connection = getConnection();
33 String sql = "select * from Student;";
34 ps = this.connection.prepareStatement(sql);
35 }
36
37 /**
38 * 程序执行完毕就可以进行,关闭连接和释放资源的动作了
39 *
40 * @throws Exception
41 */
42 @Override
43 public void close() throws Exception {
44 super.close();
45 if (connection != null) { //关闭连接和释放资源
46 connection.close();
47 }
48 if (ps != null) {
49 ps.close();
50 }
51 }
52
53 /**
54 * DataStream 调用一次 run() 方法用来获取数据
55 *
56 * @param ctx
57 * @throws Exception
58 */
59 @Override
60 public void run(SourceContext<Student> ctx) throws Exception {
61 ResultSet resultSet = ps.executeQuery();
62 while (resultSet.next()) {
63 Student student = new Student(
64 resultSet.getInt("id"),
65 resultSet.getString("name").trim(),
66 resultSet.getString("password").trim(),
67 resultSet.getInt("age"));
68 ctx.collect(student);
69 }
70 }
71
72 @Override
73 public void cancel() {
74 }
75
76 private static Connection getConnection() {
77 Connection con = null;
78 try {
79 Class.forName("com.MysqL.jdbc.Driver");
80 con = DriverManager.getConnection("jdbc:MysqL://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8", "root", "root123456");
81 } catch (Exception e) {
82 System.out.println("-----------MysqL get connection has exception , msg = "+ e.getMessage());
83 }
84 return con;
85 }
86}
Flink 程序:
1package com.zhisheng.flink;
2
3import com.zhisheng.flink.source.sourceFromMysqL;
4import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
5
6/**
7 * Desc:
8 * weixi: zhisheng_tian
9 * blog: http://www.54tianzhisheng.cn/
10 */
11public class Main2 {
12 public static void main(String[] args) throws Exception {
13 final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
14
15 env.addSource(new SourceFromMysqL()).print();
16
17 env.execute("Flink add data sourc");
18 }
19}
运行 Flink 程序,控制台日志中可以看见打印的 student 信息。
RichSourceFunction
从上面自定义的 Source 可以看到我们继承的就是这个 RichSourceFunction 类,那么来了解一下:
一个抽象类,继承自 AbstractRichFunction。为实现一个 Rich SourceFunction 提供基础能力。该类的子类有三个,两个是抽象类,在此基础上提供了更具体的实现,另一个是 ContinuousFileMonitoringFunction。
MessageAckNowledgingSourceBase :它针对的是数据源是消息队列的场景并且提供了基于 ID 的应答机制。
MultipleIdsMessageAckNowledgingSourceBase : 在 MessageAckNowledgingSourceBase 的基础上针对 ID 应答机制进行了更为细分的处理,支持两种 ID 应答模型:session id 和 unique message id。
ContinuousFileMonitoringFunction:这是单个(非并行)监视任务,它接受 FileInputFormat,并且根据 FileProcessingMode 和 FilePathFilter,它负责监视用户提供的路径;决定应该进一步读取和处理哪些文件;创建与这些文件对应的 FileInputSplit 拆分,将它们分配给下游任务以进行进一步处理。
最后
本文主要讲了下 Flink 使用 Kafka Source 的使用,并提供了一个 demo 教大家如何自定义 Source,从 MysqL 中读取数据,当然你也可以从其他地方读取,实现自己的数据源 source。可能平时工作会比这个更复杂,需要大家灵活应对!
关注我
转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/10/30/flink-create-source/
另外我自己整理了些 Flink 的学习资料,目前已经全部放到微信公众号了。你可以加我的微信:zhisheng_tian,然后回复关键字:Flink 即可无条件获取到。
相关文章
1、《从0到1学习Flink》—— Apache Flink 介绍
2、《从0到1学习Flink》—— Mac 上搭建 Flink 1.6.0 环境并构建运行简单程序入门
3、《从0到1学习Flink》—— Flink 配置文件详解
4、《从0到1学习Flink》—— Data Source 介绍
5、《从0到1学习Flink》—— 如何自定义 Data Source ?
6、《从0到1学习Flink》—— Data Sink 介绍
7、《从0到1学习Flink》—— 如何自定义 Data Sink ?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。