Flink系列二:DataStream 编程模型

    Flink 中定义了DataStream API让用户灵活且高效地编写Flink流式应用。DataStream API主要可分为三个部分,DataSource模块、Transformation模块以及DataSink模块。其中DataSource模块主要定义了数据接入功能,主要是将各种外部数据接入至Flink系统中,并将接入数据转换成对应的DataStream数据集。在Transformation模块定义了对DataStream数据集的各种转换操作,例如进行map、filter、windows等操作。最后,将结果数据通过DataSink模块写出到外部存储介质中,例如将数据输出到文件或kafka消息中间件等。

    本文详细讲述DataStream的三大模块:

  • DataSource模块

  • Transformation模块

  • DataSink模块

一、DataSource数据输入

    DataSource模块定义了DataStream API中的数据输入操作,Flink将数据源分为内置数据源和第三方数据源两种类型。

1、内置数据源

(1)文件数据源

    基于文件创建DataStream主要有两种方式:readTextFile和readFile。

    可以使用readTextFile方法直接读取文件,readTextFile提供了两个重载方法:

  • readTextFile(String filePath):逐行读取指定文件来创建DataStream,使用系统默认字符编码读取。
  • readTextFile(String filePath,String charsetName):逐行读取文件来创建DataStream,使用charsetName编码读取。

    readFile通过指定的InputFormat来读取指定数据类型的文件。对于指定路径文件,我们可以使用不同的处理模式来处理,FileProcessingMode.PROCESS_ONCE模式只会处理文件数据一次,而FileProcessingMode.PROCESS_CONTINUOUSLY会监控数据源文件是否有新数据,如果有新数据则会继续处理。

(2)socket数据源

    Flink支持从Socket端口中接入数据,在StreamExecutionEnvironment调用socketTextStream方法。该方法参数分别为Ip地址和端口,也可以同时传入字符串切割符delimiter和最大尝试次数maxRetry,其中delimiter负责将数据切割成Records数据格式;maxRetry在端口异常的情况,通过指定次数进行重连,如果设定为0,则Flink程序直接停止,不再尝试和端口进行重连。如下代码是使用socketTextStream方法实现了将数据从本地9999端口中接入数据并转换成DataStream数据集的操作。

val socketDataStream = env.socketTextStream("localhost", 9999)

(3)集合数据源

    Flink可以直接将java或Scala程序中集合类(collection)转换为DataStream数据集,本质上是将本地集合中的数据分发到远端并并行执行的节点中。目前Flink支持从Java.util.Collection和java.util.Iterator序列中转换为DataStream数据集。需要注意的是,集合中的数据结构类型必须要一致,否则可能会出现数据转换异常。

  • fromCollection - 从数组创建DataStream数据集:
val dataStream = env.fromElements(Tuple2(1L, 3L), Tuple2(1L, 5L), Tuple2(1L, 7L), Tuple2(1L, 4L))
  • 将java.util.List 转换成DataStream数据集:
String[] elements = new String[]{"hello", "flink"}
DataStream<String> dataStream = env.fromCollection(Arrays.asList(elements))
  • fromElements - 从元素集合中创建DataStream数据集:
List<String> arrayList = new ArrayList<>()
arrayList.add("hello flink")
DataStream<String> dataList = env.fromCollection(arrayList)

2、外部数据源

(1)数据源连接器

    Flink通过实现SourceFunction定义了非常丰富的第三方数据连接器,基本覆盖了大部分的高性能存储介质以及中间件等,其中一部分连接器是仅支持读取数据,例如Twitter Streaming API、Netty等;另外一部分仅支持数据输出(Sink),不支持数据输入(Source),例如Apache Cassandra、Elasticsearch、Hadoop FileSystem 等。还有一部分即支持数据输入,也支持数据输出,例如Apache Kafka、Amazon Kinesis、RabbitMQ等连接器。

(2)自定义数据源连接器

    Flink中已经实现了大多数主流的数据源连接器,但,flink的整体架构非常开放,用户可以自己定义连接器,以满足不同的数据源的接入需求。可以通过实现SourceFunction定义单个线程接入的数据接入器,也可以通过实现ParallelSourceFunction接口或继承RichParallelSourceFuntion类定义并发数据源接入器。DataSources定义完成后,可以通过使用StreamExecutionEnvironment的addSources方法添加数据源,这样就可以将外部系统中的数据转换成DataStream[T]数据集合,其中T类型是SourceFuntion返回值类型,然后就可以完成各种流式数据的转换操作。

二、DataSteam转换操作

1、Single-DataStream操作

    数据处理的核心就是对数据进行各种转化操作,数据的transformation是将一个或者多个DataStream转换成一个或者多个新的DataStream,程序可以将多个transformation操作组合成一个复杂的拓扑结构。

  • Map[DataStream -> DataStream ]: 输入一个参数产生一个参数。
  • FlatMap[DataStream -> DataStream ]:输入一个参数,产生0个、1个或者多个输出。
  • Filter[DataStream -> DataStream ]:过滤指定元素数据,如果返回true则该元素继续向下传递,如果为false则将该元素过滤掉。
  • KeyBy[DataStream -> KeyedStream ]:逻辑上将数据流元素进行分区,具有相同key的记录将被划分到同一分区。
  • Reduce[KeyedStream -> DataStream ]:对指定的“虚拟”key相同的记录进行滚动合并,也就是当前元素与最后一次的reduce结果进行reduce操作。
  • Fold[KeyedStream -> DataStream ]:Fold功能和Reduce类似,但是Fold提供了初始值,从初始值开始滚动对相同的key记录进行滚动合并。
  • Aggregations[KeyedStream -> DataStream ]:滚动聚合具有相同key的数据流元素,我们可以指定需要聚合的字段(field)。
  • window[KeyedStream->WindowedStream]: 对已经分区的KeyedStream上定义窗口,Window会根据某些规则(比如在最后5s到达的数据)对虚拟“key”相同的记录进行分组。

  • windowAll[DataStream->AllWindowedStream]: 也可以在常规DataStream上使用窗口,Window根据某些条件(比如最后5s到达的数据)对所有流事件进行分组。

  • Window Apply[WindowedStream->DataStream或AllWindowedStream->DataStream]: 将整个窗口应用在指定函数上,可以对WindowedStream和AllWindowedStream使用。

  • Window Reduce/Fold/Aggregation[WindowedStream->DataStream]: 对于WindowedStream数据流我们同样也可以应用Reduce、Fold、Aggregation函数。

2、Multi-DataStream操作

  • Union[DataStream -> DataStream ]:联合(Union)两个或多个DataStream,所有DataStream中的元素都会组合成一个新的DataStream。如果联合自身,则每个元素出现两次在新的DataStream。
  • Connect [DataStream,DataStream->ConnectedDataStreams]:连接(connect)两个流,并且保留其类型。两个数据流之间可以共享状态。
  • CoMap, CoFlatMap[ConnectedDataStreams->DataStream]:可以对连接流执行类似map和flatMap操作。
  • Split[DataStream -> SplitStream ]:可以根据某些规则将数据流切分成两个或多个数据流。
  • Select[SplitStream -> DataStream ]:可以对SplitStream分开的流进行选择,可以将其转换成一个或多个DataStream。
  • Iterate[SplitStream -> IterativeStream ]:可以使用iterate方法来获取IterativeStream。

3、物理分区操作

  • 随机分区(Random Partitioning) : [DataStream -> DataStream ]:均匀随机将元素进行分区。
  • Roundrobin Partitioning : [DataStream -> DataStream ]:以轮询的方式为每个分区均衡分配元素,对于优化数据倾斜该方法非常有效。
  • Rescaling Partitioning : [DataStream -> DataStream ]:根据上下游task数进行分区。
  • 自定义分区(Custom Partitioning): [DataStream -> DataStream ]:使用用户自定义的分区函数对指定key进行分区

三、DataSink数据输出

    Flink中将DataStream数据输出在外部系统的过程被定义为DataSink操作。在Flink内部定义的第三方外部系统连接器中,支持数据输出的有Apache Kafka、Apache Cassandra、ElasticSearch、Hadoop FileSystem、RabbitMQ、NIFI等。

1、基本数据输出

    基本数据输出包含了文件输出、客户端输出、Socket网络端口等。如下代码所示,实现将DataStream数据集分别输出在本地文件系统和Socket网络端口。

val person = env.fromElements(("alex", 18), ("peter", 11))
person.writeAsCsv("file:///path/to/person.csv", WriteMode.OVERWRITE)
person.writeToSocket(outputHost, outputPort, new SimpleStringSchema())

2、第三方数据输出

    Flink中提供了DataSink类操作算子来专门处理数据的输出,所有的数据输出都可以基于实现SinkFunction完成定义。例如在Flink中定义了FlinkKafkaProducer类来完成将数据输出到kafka的操作,需要根据不同的kafka版本选择不同的FlinkKafkaProducer。如下代码所示,通过FlinkKafkaProducer11将DataStream中的数据写入kafka的topic中。

val wordStream = env.fromElements("alex", "peter", "linda")
val kafkaProducer = new FlinkKafkaProducer011[string]("localhost:9092", "kafka-topic", new SimpleStringSchema)
wordStream.addSink(kafkaProducer)

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值