Flink DataStream API指南【翻译】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37142346/article/details/83048895

1.什么是DataStream?

DataStream是Flink中可以在数据流的基础上实现各种transformation操作的程序,(比如filtering,updating state,defining windows,aggregating)。这些数据流最初的来源可以有很多种,比如消息队列,socket流,文件等,计算的结果通过sinks途径返回,你也可以写这些数据到一个文件或者标准的输出系统中(比如命令行控制台)。Flink程序可以运行在一个文件(本地测试),standalone模式或者嵌入其他程序等多种方式,Flink程序的执行发生在一个local JVM或者一个集群的许多机器上。

在介绍DataStream API之前,我们先了解一下Flink程序的基本流程。

2.Flink Program

Flink程序像常规的程序一样对数据集合进行转换操作,每个程序由下面几部分组成:

  1. 获取一个执行环境
  2. 加载/创建初始化数据
  3. 指定对于数据的transformations操作
  4. 指定计算的输出结果(打印或者输出到文件)
  5. 触发程序执行

StreamExecutionEnvironment 是所有Flink程序的基础,你可以使用StreamExecutionEnvironment类的静态方法来获取,有以下三个静态方法:

getExecutionEnvironment()

createLocalEnvironment()

createRemoteEnvironment(String host, int port, String... jarFiles)

典型地,当你依赖于文本实现一些计算时,你需要使用getExecutionEnvironment()来获取;如果执行程序在IDE或者java程序中时可以创建一个本地环境变量来执行触发程序;如果需要打包程序jar包运行,可以使用命令行提交,如下命令所示:

./bin/flink run ./examples/batch/WordCount.jar

可以通过执行环境来指定数据源,有多种数据源可以指定,比如命令行,CSV文件读取,使用消息队列消费等格式,比如读取一个文本文件的数据:

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

DataStream<String> text = env.readTextFile("file:///path/to/file");

接着你可以使用DataStream的transformation方法来对数据进行操作,比如下面的实例,将源数据转换为Integer格式数据:

DataStream<String> input = ...;

DataStream<Integer> parsed = input.map(new MapFunction<String, Integer>() {
    @Override
    public Integer map(String value) {
        return Integer.parseInt(value);
    }
});

接着你可以将计算的结果打印在控制台或者写入某个文件,比如下面的写法:

writeAsText(String path)

print()

最后,我们需要使用运行环境变量Env调用execute方法来触发Flink程序的执行。

下面通过一个简单的WordCount程序来看看Flink程序的基本写法与执行结果,如果你使用的IDE来编写程序,需要导入下面maven依赖,Flink版本使用的是最新版本1.6.1。

<dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-scala_2.11</artifactId>
      <version>${flink.version}</version>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-streaming-scala_2.11</artifactId>
      <version>${flink.version}</version>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-core</artifactId>
      <version>${flink.version}</version>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-clients_2.11</artifactId>
      <version>${flink.version}</version>
      <scope>compile</scope>
    </dependency>

    
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-connector-kafka-0.10_2.11</artifactId>
      <version>${flink.version}</version>
    </dependency>

程序使用Scala编写(会scala的话java照着翻译就行,很简单),WordCount程序如下所示:

import org.apache.flink.api.scala._
import org.apache.flink.core.fs.FileSystem.WriteMode

/**
  * 可以直接本地运行
  */
object WordCount {

  def main(args: Array[String]) {
    val env = ExecutionEnvironment.createLocalEnvironment(1)

    //从本地读取文件
    val text = env.readTextFile("F:\\FlinkProject\\src\\main\\scala\\cn\\just\\shinelon\\data\\word.txt")

    //单词统计
    val counts = text.flatMap { _.toLowerCase.split("\\W+") filter { _.nonEmpty } }
      .map { (_, 1) }
      .groupBy(0)   //按照第一个字段分组
      .sum(1)       //第二个字段求和

    //输出结果
    counts.print()

    //保存结果到txt文件
    counts.writeAsText("F:\\FlinkProject\\src\\main\\scala\\cn\\just\\shinelon\\print\\wordcount.txt", WriteMode.OVERWRITE)
    env.execute("Scala WordCount Example")

  }
}

程序执行结果如下所示:
在这里插入图片描述

3.数据源

3.1文本文件

你可以绑定一个数据源到你的程序使用StreamExecutionEnvironment.addSource(sourceFunction)。
下面有几种数据源的输入格式API可以使用StreamExecutionEnvironment来调用:

readTextFile(path):读取一个文本文件,输入文件可以指定输入格式
readFile(fileInputFormat, path):从指定目录读取文件
readFile(fileInputFormat, path, watchType, interval, pathFilter, typeInfo):这个方法在指定文件格式的基础上读取文件,依赖于watchType,它可以通过执行interval(ms为单位)爱周期性的监控目录下产生的新的数据。主要有两种文件处理模式:(FileProcessingMode.PROCESS_CONTINUOUSLY)模式和(FileProcessingMode.PROCESS_ONCE)

注意:

  1. 如果watchType设置为FileProcessingMode.PROCESS_CONTINUOUSLY,当一个文件被修改,它的整个文本内容将会全部被重新执行,这样会破坏"exactly-once"语义(不懂的可以查一下,也可以参考我的手记【Spark Streaming容错性分析】)。当在文件末尾增加新的数据时整个文件都将会被重新处理一次。
  2. 如果watchType设置为FileProcessingMode.PROCESS_ONCE,它将会扫描已经存在在路径中的文件,不会等等待reader区完成读取文件内容,不过reader会一直读取数据直到读完整个文件。
3.2 socket流数据
socketTextStream :从socket读取数据,元素之间按照指定分隔符分割
3.3 集合数据

主要有以下API:

fromCollection(Collection):创建一个数据流从Java.util.Collection,集合中的所有元素必须指定相同的类型
fromCollection(Iterator, Class):使用iterator创建一个数据流,通过class指定iterator元素的数据类型
fromElements(T ...):使用对象队列来创建数据流,所有的对象必须有相同的类型。
fromParallelCollection(SplittableIterator, Class) :使用并行方式的iterator
generateSequence(from, to) :生成一个指定范围的数字队列
3.4 Consumer
addSource :绑定一个kafka Consumer,比如addSource(new FlinkKafkaConsumer08<>(...))

4. DataStream Transformations

详情可以查看文档transformation operations

5. Data Sink

主要有以下API:

writeAsText() / TextOutputFormat:写入一个文本文件
writeAsCsv(...) / CsvOutputFormat:写入一个CSV格式文件
print() / printToErr():输出打印到控制台
writeUsingOutputFormat() / FileOutputFormat :支持对象到字节的转换
writeToSocket:写一个元素到socket根据SerializationSchema
addSink:调用一个custom sink方法,也可以绑定其他系统,比如kafka

6. Iteratoins

迭代流程序实现了一个步进函数并且嵌入它到一个IterativeStream中,一个DataStream程序也许永远也不会执行完毕,它没有迭代的最大次数,不过,你必须使用一个split transformation或者filter来反馈到iteration函数,可以通过下面方式创建使用:

IterativeStream<Integer> iteration = input.iterate();

DataStream<Integer> iterationBody = iteration.map(/* this is executed many times */);

下面通过一个简单的案例来说明:

import org.apache.flink.streaming.api.scala._

/**
  * 测试迭代流程序
  * 0-1000的每一个整数迭代减1
  */
object SubtractIterator {
  def main(args: Array[String]): Unit = {
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    val someIntegers = env.generateSequence(0,1000)

    val iteratedStream = someIntegers.iterate(iteration =>{
      //map transformation
      val minusOne = iteration.map(x=>x-1)
      //filter
      val stillGreaterThanZero = minusOne.filter (_ > 0)
      val lessThanZero = minusOne.filter(_ <= 0)
      (stillGreaterThanZero, lessThanZero)
    })

    iteratedStream.print()

    env.execute("SubtractIterator")

  }

}

7.执行参数

StreamExecutionEnvironment 的方法ExecutionConfig 允许设置程序运行时参数。比如:

setAutoWatermarkInterval(long milliseconds):设置发射流自动标记间隔,也可以获取当前值使用方法long getAutoWatermarkInterval()

8.容错机制

Flink可以使用state&Checkpoint机制进行容错,可以参考文档State&CheckPoint
不过还有一些隐患需要注意,默认的,元素不能在网络之间一个一个的进行传输,但是它可以通过buffer的形式,buffer的大小可以通过Flink的配置文件设置,我们可以设置最佳的数据吞吐量,但是它也有可能会造成一个隐患是输入流不是足够快,为了协调吞吐量和这个隐患,我们可以使用env.setBufferTimeout(timeoutMillis) 来设置一个最大等待时间来等待buffer填满数据,如果等待超时,buffer会自动发送事件即使buffer还没有填满,默认的超时时间是100ms。例如:

LocalStreamEnvironment env = StreamExecutionEnvironment.createLocalEnvironment();
env.setBufferTimeout(timeoutMillis);

env.generateSequence(1,10).map(new MyMapper()).setBufferTimeout(timeoutMillis);

为了设置最大的吞吐量,你可以设置setBufferTimeout(-1)来取消超时等待只有当buffer填满了才发送,当然你也可以设置为0来避免上述隐患,加快输入流的速度,不过这样会导致性能严重下降。

以上是参考官方文档的翻译文章,本人水平有限,如有不足之处还请指教。
官方文档 Flink DataStream API Programming Guide

猜你喜欢

转载自blog.csdn.net/qq_37142346/article/details/83048895