Flink的DataSource三部曲之二:內建connector

程式設計師欣宸發表於2020-11-06

歡迎訪問我的GitHub

https://github.com/zq2599/blog_demos

內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等;

本篇概覽

本文是《Flink的DataSource三部曲》系列的第二篇,上一篇《Flink的DataSource三部曲之一:直接API》學習了StreamExecutionEnvironment的API建立DataSource,今天要練習的是Flink內建的connector,即下圖的紅框位置,這些connector可以通過StreamExecutionEnvironment的addSource方法使用:

在這裡插入圖片描述
今天的實戰選擇Kafka作為資料來源來操作,先嚐試接收和處理String型的訊息,再接收JSON型別的訊息,將JSON反序列化成bean例項;

Flink的DataSource三部曲文章連結

  1. 《Flink的DataSource三部曲之一:直接API》
  2. 《Flink的DataSource三部曲之二:內建connector》
  3. 《Flink的DataSource三部曲之三:自定義》

原始碼下載

如果您不想寫程式碼,整個系列的原始碼可在GitHub下載到,地址和連結資訊如下表所示(https://github.com/zq2599/blog_demos):

名稱 連結 備註
專案主頁 https://github.com/zq2599/blog_demos 該專案在GitHub上的主頁
git倉庫地址(https) https://github.com/zq2599/blog_demos.git 該專案原始碼的倉庫地址,https協議
git倉庫地址(ssh) git@github.com:zq2599/blog_demos.git 該專案原始碼的倉庫地址,ssh協議

這個git專案中有多個資料夾,本章的應用在flinkdatasourcedemo資料夾下,如下圖紅框所示:
在這裡插入圖片描述

環境和版本

本次實戰的環境和版本如下:

  1. JDK:1.8.0_211
  2. Flink:1.9.2
  3. Maven:3.6.0
  4. 作業系統:macOS Catalina 10.15.3 (MacBook Pro 13-inch, 2018)
  5. IDEA:2018.3.5 (Ultimate Edition)
  6. Kafka:2.4.0
  7. Zookeeper:3.5.5

請確保上述內容都已經準備就緒,才能繼續後面的實戰;

Flink與Kafka版本匹配

  1. Flink官方對匹配Kafka版本做了詳細說明,地址是:https://ci.apache.org/projects/flink/flink-docs-stable/dev/connectors/kafka.html
  2. 要重點關注的是官方提到的通用版(universal Kafka connector ),這是從Flink1.7開始推出的,對於Kafka1.0.0或者更高版本都可以使用:

在這裡插入圖片描述
3. 下圖紅框中是我的工程中要依賴的庫,藍框中是連線Kafka用到的類,讀者您可以根據自己的Kafka版本在表格中找到適合的庫和類:

在這裡插入圖片描述

實戰字串訊息處理

  1. 在kafka上建立名為test001的topic,參考命令:
./kafka-topics.sh \
--create \
--zookeeper 192.168.50.43:2181 \
--replication-factor 1 \
--partitions 2 \
--topic test001
  1. 繼續使用上一章建立的flinkdatasourcedemo工程,開啟pom.xml檔案增加以下依賴:
<dependency>
  <groupId>org.apache.flink</groupId>
  <artifactId>flink-connector-kafka_2.11</artifactId>
  <version>1.10.0</version>
</dependency>
  1. 新增類Kafka240String.java,作用是連線broker,對收到的字串訊息做WordCount操作:
package com.bolingcavalry.connector;

import com.bolingcavalry.Splitter;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import java.util.Properties;
import static com.sun.tools.doclint.Entity.para;

public class Kafka240String {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        //設定並行度
        env.setParallelism(2);

        Properties properties = new Properties();
        //broker地址
        properties.setProperty("bootstrap.servers", "192.168.50.43:9092");
        //zookeeper地址
        properties.setProperty("zookeeper.connect", "192.168.50.43:2181");
        //消費者的groupId
        properties.setProperty("group.id", "flink-connector");
        //例項化Consumer類
        FlinkKafkaConsumer<String> flinkKafkaConsumer = new FlinkKafkaConsumer<>(
                "test001",
                new SimpleStringSchema(),
                properties
        );
        //指定從最新位置開始消費,相當於放棄歷史訊息
        flinkKafkaConsumer.setStartFromLatest();

        //通過addSource方法得到DataSource
        DataStream<String> dataStream = env.addSource(flinkKafkaConsumer);

        //從kafka取得字串訊息後,分割成單詞,統計數量,視窗是5秒
        dataStream
                .flatMap(new Splitter())
                .keyBy(0)
                .timeWindow(Time.seconds(5))
                .sum(1)
                .print();

        env.execute("Connector DataSource demo : kafka");
    }
}
  1. 確保kafka的topic已經建立,將Kafka240執行起來,可見消費訊息並進行單詞統計的功能是正常的:

在這裡插入圖片描述
5. 接收kafka字串訊息的實戰已經完成,接下來試試JSON格式的訊息;

實戰JSON訊息處理

  1. 接下來要接受的JSON格式訊息,可以被反序列化成bean例項,會用到JSON庫,我選擇的是gson;
  2. 在pom.xml增加gson依賴:
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.5</version>
</dependency>
  1. 增加類Student.java,這是個普通的Bean,只有id和name兩個欄位:
package com.bolingcavalry;

public class Student {

    private int id;

    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. 增加類StudentSchema.java,該類是DeserializationSchema介面的實現,將JSON反序列化成Student例項時用到:
ackage com.bolingcavalry.connector;

import com.bolingcavalry.Student;
import com.google.gson.Gson;
import org.apache.flink.api.common.serialization.DeserializationSchema;
import org.apache.flink.api.common.serialization.SerializationSchema;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import java.io.IOException;

public class StudentSchema implements DeserializationSchema<Student>, SerializationSchema<Student> {

    private static final Gson gson = new Gson();

    /**
     * 反序列化,將byte陣列轉成Student例項
     * @param bytes
     * @return
     * @throws IOException
     */
    @Override
    public Student deserialize(byte[] bytes) throws IOException {
        return gson.fromJson(new String(bytes), Student.class);
    }

    @Override
    public boolean isEndOfStream(Student student) {
        return false;
    }

    /**
     * 序列化,將Student例項轉成byte陣列
     * @param student
     * @return
     */
    @Override
    public byte[] serialize(Student student) {
        return new byte[0];
    }

    @Override
    public TypeInformation<Student> getProducedType() {
        return TypeInformation.of(Student.class);
    }
}
  1. 新增類Kafka240Bean.java,作用是連線broker,對收到的JSON訊息轉成Student例項,統計每個名字出現的數量,視窗依舊是5秒:
package com.bolingcavalry.connector;

import com.bolingcavalry.Splitter;
import com.bolingcavalry.Student;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import java.util.Properties;

public class Kafka240Bean {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        //設定並行度
        env.setParallelism(2);

        Properties properties = new Properties();
        //broker地址
        properties.setProperty("bootstrap.servers", "192.168.50.43:9092");
        //zookeeper地址
        properties.setProperty("zookeeper.connect", "192.168.50.43:2181");
        //消費者的groupId
        properties.setProperty("group.id", "flink-connector");
        //例項化Consumer類
        FlinkKafkaConsumer<Student> flinkKafkaConsumer = new FlinkKafkaConsumer<>(
                "test001",
                new StudentSchema(),
                properties
        );
        //指定從最新位置開始消費,相當於放棄歷史訊息
        flinkKafkaConsumer.setStartFromLatest();

        //通過addSource方法得到DataSource
        DataStream<Student> dataStream = env.addSource(flinkKafkaConsumer);

        //從kafka取得的JSON被反序列化成Student例項,統計每個name的數量,視窗是5秒
        dataStream.map(new MapFunction<Student, Tuple2<String, Integer>>() {
            @Override
            public Tuple2<String, Integer> map(Student student) throws Exception {
                return new Tuple2<>(student.getName(), 1);
            }
        })
                .keyBy(0)
                .timeWindow(Time.seconds(5))
                .sum(1)
                .print();

        env.execute("Connector DataSource demo : kafka bean");
    }
}
  1. 在測試的時候,要向kafka傳送JSON格式字串,flink這邊就會給統計出每個name的數量:

在這裡插入圖片描述
至此,內建connector的實戰就完成了,接下來的章節,我們將要一起實戰自定義DataSource;

歡迎關注公眾號:程式設計師欣宸

微信搜尋「程式設計師欣宸」,我是欣宸,期待與您一同暢遊Java世界...
https://github.com/zq2599/blog_demos

相關文章