Flink 常用API

314 阅读5分钟

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

常用API

DataStream 常用API

主要分成三块 DataSource Transformation Sink

DataSource

主要有四种

基于文件

env.readTextFile("fileName");

也可以用hdfs

env.readTextFile("hdfs://teacher1:9000/a.txt")

但要多设置几步, 在windows环境中安装hadoop, 并且新增依赖

System.setProperty("HADOOP_USER_NAME","");

依赖方面主要有:

flink-hadoop-compatibility_2.11, hadoop-common, hadoop-hdfs, hadoop-client

基于Socket

从Socket中读取数据, 元素可以通过一个分割符分开

基于集合

通过java的Collection集合创建一个数据流, 集合中的所有元素必须是相同类型

env.fromCollection(Collection);
env.fromElements("A", "B");

如果满足一下条件,Flink将数据类型识别为POJO类型(允许按名称字段引用)

  • 公有且独立(没有非静态内部类)
  • 有公有的无参构造方法
  • 类(及父类)中所有的不被static,transient修饰的属性要么是公有的(且不被final修饰), 要么是包含公有的getter和setter方法,遵循Java Bean命名规范

自定义

addSource实现读取第三方数据源, Flink提供了一批内置的Connector(连接器)

连接器是否提供Source支持是否提供Sink支持
Apache Kafka
ElasticSearch
HDFS
Twitter Streaming PI

kafka连接器

<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-connector-kafka_2.12</artifactId>
    <version>1.13.1</version>
</dependency>
Properties properties = new Properties();
properties.setProperty("boostrap.servers", "teacher2:9092");
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnviroment();
FlinkKafkaConsumer consumer = new FlinkKafkaConsumer("topicName", new SimpleStringSchema(), properties);
DataStreamSource<String> data = env.addSource(consumer);

Transformation

  • Map: 输入一个元素, 返回一个元素,中间可以进行清洗转换操作

  • FlatMap: 输入一个元素,可以返回0个, 1个或者多个元素

  • Filter: 过滤函数,对传入的数据进行判断, 符合条件的数据留下

  • KeyBy : 根据指定的Key进行分组, Key相同的数据会进入同一个分区

    KeyBy 有两种用法

    • DataStream.keyBy("someKey")指定对象中的someKey字段作为分组Key
    • DataStream.keyBy(0) 指定Tuple中的第一个元素作为分组Key
  • Reduce: 对数据进行聚合操作, 结合当前元素和上一次返回的值进行聚合操作,返回新值

  • Aggregations: sum() min() max()等

Sink

  • writeAsText(): 将元素以字符串形式逐行写入, 通过调用toString()方法获取
  • print()/printToErr(): 打印到标准输出或者标准错误输出流中
  • 自定义 addSink 输出第三方介质

DataSet常用API

DataStream

  • 基于集合 fromCollection(Collection)
  • 基于文件 readTextFile(path), 基于HDFS数据\

Transformation

  • Map
  • FlatMap
  • Filter
  • Reduce
  • Aggregations: sum() min() max()

SInk

  • WriteAsText()
  • WriteAsCsv()
  • print()/printToErr()

窗口机制

窗口可以是基于时间驱动的,也可以是基于数据驱动的, 可以分为 翻滚窗口(Tumbling Window), 滑动窗口(Sliding Window), 会话窗口(Session Window), 全局窗口

Flink Time

EventTime【事件时间】

IngestionTime【摄入时间】 进入source

ProcessingTime【处理时间】

env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);

此时窗口需要考虑到事件时间, 使用watermark解决

watermark

水印(watermark)就是一个时间戳,Flink可以给数据流添加水印,

可以理解为:收到一条消息后,额外给这个消息添加了一个时间字段,这就是添加水印。

- 水印并不会影响原有Eventtime事件时间

- 当数据流添加水印后,会按照水印时间来触发窗口计算

也就是说watermark水印是用来触发窗口计算的

- 一般会设置水印时间,比事件时间小几秒钟,表示最大允许数据延迟达到多久

(即水印时间 = 事件时间 - 允许延迟时间)10:09:57 = 10:10:00 - 3s

- 当接收到的 水印时间 >= 窗口结束时间,则触发计算 如等到一条数据的水印时间为10:10:00 >= 10:10:00 才触发计算,也就是要等到事件时间为10:10:03的数据到来才触发计算

(即事件时间 - 允许延迟时间 >= 窗口结束时间 或 事件时间 >= 窗口结束时间 + 允许延迟时间)

并行度

一个Operator由多个并行的task线程执行, 一个Operator的并行Task数目被称为并行度

并行度可以有几种指定方式

  • Operator Level 算子级别
  • ExecutionEnvironment
  • Client Level 客户端 命令端 -p
  • System Level flink-conf.yaml文件中parallelism.default

source不可以被并行执行, 设置了也不会生效

尽可能规避算子并行度设置,因为会造成task的重新划分, 带来shuffer问题

推荐使用任务提交的时候 动态指定并行度

slot是静态的概念,指taskManager具有的并发执行能力, parallelism是动态概念,程序运行时实际使用的并发能力.

Flink-Kafka

1.1 消费策略

  • setStartFromGroupOffsets()【默认消费策略】

    默认读取上次保存的offset信息 如果是应用第一次启动,读取不到上次的offset信息,则会根据这个参数auto.offset.reset的值来进行消费数据

  • setStartFromEarliest() 从最早的数据开始进行消费,忽略存储的offset信息

  • setStartFromLatest() 从最新的数据进行消费,忽略存储的offset信息

  • setStartFromSpecificOffsets(Map<KafkaTopicPartition, Long>) 从指定位置进行消费

  • 当checkpoint机制开启的时候,KafkaConsumer会定期把kafka的offset信息还有其他operator的状态信息一块保存起来。当job失败重启的时候,Flink会从最近一次的checkpoint中进行恢复数据,重新消费kafka中的数据。

  • 为了能够使用支持容错的kafka Consumer,需要开启checkpoint env.enableCheckpointing(5000); // 每5s checkpoint一次

1.2 Kafka consumer offset自动提交:

kafka consumer offset自动提交的配置需要根据job是否开启checkpoint来区分

checkpoint关闭时:

checkpoint开启时:

如果启用了checkpoint,并且启用了checkpoint完成时提交offset,返回ON_CHECKPOINTS。

如果未启用checkpoint,但是启用了自动提交,返回KAFKA_PERIODIC。

其他情况都返回DISABLED。

OffsetCommitMode是一个枚举类型,具有如下三个值:

  • DISABLED:完全禁用offset提交。
  • ON_CHECKPOINTS:当checkpoint完成的时候再提交offset。
  • KAFKA_PERIODIC:周期性提交offset。

Flink-Kafka-Consumer:

package com.lagou.source;

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.connectors.kafka.FlinkKafkaConsumer;

import java.util.Properties;

public class FromKafka {
    public static void main(String[] args) throws Exception {
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
            Properties properties = new Properties();
            properties.setProperty("bootstrap.servers", "teacher2:9092");

            FlinkKafkaConsumer<String> consumer = new FlinkKafkaConsumer<>("mytopic", new SimpleStringSchema(), properties);
            //从最早开始消费
            consumer.setStartFromEarliest();
            DataStream<String> stream = env.addSource(consumer);
            stream.print();
            //stream.map();
            env.execute();


    }
}

Flink kafka Producer

代码:

package com.lagou.sink;

import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer;

import java.util.Properties;

public class SinkToKafka {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> data = env.socketTextStream("192.168.1.3", 7777);
        Properties properties = new Properties();
        properties.setProperty("bootstrap.servers","teacher2:9092");
        FlinkKafkaProducer producer = new FlinkKafkaProducer("teacher2:9092", "mytopic2", new SimpleStringSchema());
        data.addSink(producer);
        env.execute();
    }
}