DataStream API使用
DataStream编程模型
DataStream API主要可以分为三个部分,DataSource模块、Transformation模块以及DataSink模块,其中Sources模块主要定义了数据接入功能,主要是将各种外部数据接入至Flink系统中,并将数据转换成对应的DataStream数据集。在Transformation模块定义了对DataStream数据集的各种转换操作,例如进行map、filter、windows等操作。最后将结果数据通过DataSink模块写出,例如将数据输出到文件或者Kafka消息中间件。
DataSources数据输入
Flink将数据源分为内置数据源和第三方数据源两种类型。内置数据源包括文件、Socket网络端口以及集合类型数据,用户可以直接调用相关方法使用。第三方数据源定义了Flink和外部系统数据交互的逻辑,包括数据的读写接口。在Flink中定义了第三方数据源连接器(Connector),有Kafka Connector、Elatic Search Connector等。同时用户可以自定义实现Flink中数据接入函数SourceFunction,并封装成第三方数据源的Connector,完成与其他外部系统的数据交互。
内置数据源
-
文件数据源
在StreamExecutionEnvironment中,可以使用readTextFile方法直接读取文本文件,也可以使用readFile方法通过制定文件InputFormat来读取特定数据类型的文件,其中InputFormat可以是已经定义的,如CsvInputFormat,也可以用户自定义实现InputFormat接口类。 -
Socket数据源
调用socketTextStream方法,方法参数为ip地址和端口,(和spark Streaming)相似。 -
集合数据源
Flink可以直接将Java或Scala程序中集合类(Collection)转换成DataStream数据集,本质上是将本地集合中的数据分发到远端并行执行的结点中。目前Flink支持从Java.util.Collection和java.util.Iterator序列中转换DataStream数据集。
外部数据源
Flink通过实现SourceFunction定义了非常丰富的第三方数据连接器,其中部分连接器仅支持读取数据,例如Twitter Streaming API、Netty等,一部分仅支持数据输出(Sink),不支持数据输入(Source),例如Apache Cassandra、Elasticsearch、Hadoop FileSystem等。还有一部分支持数据输入,也支持数据输出Kafka、Kinesis、RabbitMQ。
- kafka
用户在使用过程中,需要使用Maven把依赖库引入到应用工程中,kafka Connector中主要是用的参数有kafka topic、bootstrap.servers、zookeeper.connect。
DataStream转换操作
所有的DataStream转换操作可以分为单Single-DataStream、Muti-DataStream、物理分区三类类型。其中Single-DataStream操作定义了对单个DataStream数据集元素的处理逻辑,Multi-DataStream操作定义了对多个DataStream数据集元素的处理逻辑。物理分区定义了对数据集中的并行度和数据分区调整转换的处理逻辑。
- Single-DataStream操作,有Map、FlatMap、Filter、KeyBy、Reduce、Aggregations
- Multi-DataStream操作,有Union、Connect、CoMap、CoFlatMap、Split、Select、Iterate
- 物理分区操作,根据指定的分区策略将数据重新分配到不同节点的Task实例上执行。随机分区Random Partitioning、平衡分区Roundobin Partitioning、按比例分区Roundrobin Partitioning等
DataSinks数据输出
在Flink内部定义的第三方外部系统连接器中,支持数据输出的有Apache Kafka、Apache Cassandra、Kinesis、ElasticSearch、Hadoop FileSystem、RabbitMQ、NIFI。
时间概念和Watermark
Flink根据时间产生的位置不同,将时间区分为三种时间概念,分别为事件生成时间(Event Time)、事件接入时间(Ingestion Time)、和事件处理时间(Processing Time)。数据从终端产生,或者从系统中产生的过程中生成的时间为事件的发生时间,当数据经过消息中间件传入到Flink系统中,在DataSource中接入的时候会生成事件接入时间,当数据在Flink系统中通过各个算子实施执行转换操作的过程中,算子实例所在系统的时间为数据处理时间。
事件时间
事件时间是每个独立时间在产生它的设备上发生的时间,这个时间通常在事件进入Flink之前就已经嵌入到事件中,时间顺序取决于事件产生的地方,和下游数据处理系统的时间无关。数据处理过程依赖于数据本身产生的时间,可以还原事件的先后关系。
接入时间
接入时间是数据进入Flink系统的时间,Ingestion Time依赖于Source Operator所在主机的系统时钟。其具有一定的可预见性,在数据接入过程生成后,时间戳就不在发生变化,和后续数据处理Operator所在的机器的时钟没有关系,从而不会因为某台机器时钟不同步或网络时延而导致计算结果不准确。需要注意的是,介入时间不能处理乱序事件。
处理时间
处理时间是指数据在操作算子计算过程中获取到的所在主机时间。对接入到系统中的数据时间相关的计算完全交给算子内部决定,时间窗口计算依赖的时间都是在具体算子运行的过程中产生,不需要做任何时间上的对比和协调。适合用于时间计算精度要求不是特别高的计算场景。
EvenTime和Watermark
通常情况下,由于网络和系统等外部因素影响下,事件数据往往不能及时传输至Flink系统中,导致系统的不稳定而造成数据乱序到达或者延迟到达等问题。需要一种机制来控制数据处理的进度。创建一个基于事件时间的Window,需要确定属于该Window的数据元素是否已经全部到达,确定后才可以对Window中的所有数据做计算处理,如果数据并没有全部到达,则继续等待该窗口中的数据全部到达后再开始处理。 需要用到水位线Watermarks机制,它能衡量数据处理进度(表达数据到达的完整性),保证事件数据全部到达Flink系统,即使数据乱序或者延迟到达,也能够像预期一样计算出正确和连续的结果。
将最新的事件时间减去固定时间间隔作为Watermark,该时间间隔为用户外部配置的支持最大延迟到达的时间长度。设定时间间隔为5s,算子根据接入算子中最新时间的时间减去5s来更新其水位线时间戳,当窗口结束时间大于Operator水位线时间戳,且窗口中有事件数据,则立即触发窗口进行计算。总体来说,水位线的作用就是告知Operator在后面不会再有小于等于水位线时间戳的时间接入,满足条件即可触发窗口计算。
Window窗口计算
Windows计算是流式计算中非常常用的数据计算方式之一,通过按照固定时间或长度将数据流切分成不同的窗口,然然后对数据进行相应的聚合运算,从而得到一定时间范围内的统计结果。
Windows Assigner
Windows Assigner指定窗口的类型,可以是Keyed或Non-Keyed窗口,也可以是基于事件的窗口、基于数量的窗口。
通过Windows Assigner将接入数据分配到不同的窗口,根据数据分配方式的不同,将Windows分为4大类:滚动窗口、滑动窗口、会话窗口、全局窗口。
Windows Function
对数据集定义Windows Assigner之后,下一步要定义窗口内数据的计算逻辑。Window Function,Flink定义了四种类型,分别是ReduceFunction、AggregateFunction、FoldFunction以及ProcessWindowFunction。
根据计算原理的不同可以分为两大类,一类是增量聚合函数是ReduceFunction、AggregateFunction、FoldFunction,另一类是全量窗口函数ProcessWindowFunction。
全量窗口函数需要对窗口内的所有接入数据进行缓存,等到窗口触发,然后对所有原始数据进行汇总计算。
Trigger窗口触发器
每种类型的窗口都有对应的窗口触发机制。
- EventTimeTrigger,通过对比Watermark和窗口EndTime确定是否触发窗口
- ProcessTimeTrigger,通过对比ProcessTime和窗口EndTime确定是否触发窗口
- ContinuousEventTimeTrigger,根据间隔时间周期性触发窗口
- CountTrigger,根据接入数据量是否超过设定的阈值