Flink
一 FLink概述
Flink 是一个开源的分布式流式处理框架:
①在出现无序或者延迟加载的数据的情况下提供准确的结果。
②大规模运行,在上千个节点运行时有很好的吞吐量和低延迟。
- Flink 保证状态化计算强一致性。”状态化“意味着应用可以维护随着时间推移已经产生的数据聚合或者,并且 Flink 的检查点机制在一次失败的事件中一个应用状态的强一致性。
- Flink 支持流式计算和带有事件时间语义的视窗。事件时间机制使得那些事件无序到达甚至延迟到达的数据流能够计算出精确的结果。
- 除了提供数据驱动的视窗外,Flink 还支持基于时间,计数,session 等的灵活视窗。视窗能够用灵活的触发条件定制化从而达到对复杂的流传输模式的支持。Flink 的视窗使得模拟真实的创建数据的环境成为可能。
二 Flink学习
2.1 Data Source
Data Sources 即数据的来源。
可以使用 StreamExecutionEnvironment.addSource(sourceFunction)
添加数据来源( 自定义数据源)
StreamExecutionEnvironment 中可以使用以下几个已实现的 stream sources
- 基于集合
fromCollection(Collection):从Java.util.Collection创建数据流,集合中的所有元素类型必须相同。
- 基于文件
readTextFile(path):读取文本文件,即符合TextInputFormat规范的文件,并将其作为字符串返回。
- 基于 Socket
socketTextStream(String hostname, int port):从socket读取,元素可以用分隔符切分。
- 自定义
addSource:添加一个新的source function,例如addSource(new FlinkKafkaConsumer011<>(…))从Kafka读取数据
2.2 Data Sink
Data Sink即数据的去向。
可以看到有 Kafka,ElasticSearch,Socket,RabbitMQ,JDBC,Cassandra,File,Print 等 Sink 的方式。
自定义sink可继承了RichSinkFunction 抽象类,实现其中的方法来实现
2.3 Data transformation
Transformation:数据转换的各种操作,有 Map / FlatMap / Filter / KeyBy / Reduce / Aggregations / Window / WindowAll / Union / join / Split / Select / Project 等。
map:采用一条记录并输出一条记录
flatMap:采用一条记录并输出零个,一个或多个记录
filter:判断过滤结果或中间数据
keyBy:对数据流根据key进行相应分区
reduce:对分组数据流进行聚合求值
Aggregations:包括sum,min,max,minBy,maxBy等聚合操作
Window:按时间或其他条件对现有 KeyedStream 进行分组(timeWindow,countWindow等)
Union:函数将两个或多个数据流结合在一起
join:通过一些 key 将同一个 window 的两个数据流 join 起来
Split:数据流拆分
select:拆分流中选择特定流
Project:从事件流中选择属性子集,并仅将所选元素发送到下一个处理流
···
2.4 Stream Windows
Window 就是用来对一个无限的流设置一个有限的集合,在有界的数据集上进行操作的一种机制。window 又可以分为基于时间(Time-based)的 window 以及基于数量(Count-based)的 window。
Flink DataStream API 提供了 Time 和 Count 的 window。
1.Time Window
Time Windows 根据时间来聚合流数据:
tumbling time window(翻滚时间窗口):timeWindow(Time.minutes(1)) //tumbling time window 每分钟统计一次数量和
sliding time window(滑动时间窗口):timeWindow(Time.minutes(1), Time.seconds(30)) //sliding time window 每隔 30s 统计过去一分钟的数量和
2.Count Window
CountWindows 提供计数窗口功能:
tumbling count window(翻滚计数窗口):countWindow(100) //统计每 100 个元素的数量之和
silding count window(滑动计数窗口):countWindow(100, 10) //每 10 个元素统计过去 100 个元素的数量之和
3.自定义 Window
2.5 Time详解
Flink 在流程序中支持不同的 Time 概念,就比如有 Processing Time、Event Time 和 Ingestion Time。
Processing Time
Processing Time 是指事件被处理时机器的系统时间。
当流程序在 Processing Time 上运行时,所有基于时间的操作(如时间窗口)将使用当时机器的系统时间。每小时 Processing Time 窗口将包括在系统时钟指示整个小时之间到达特定操作的所有事件。
Processing Time 是最简单的 “Time” 概念,不需要流和机器之间的协调,它提供了最好的性能和最低的延迟。但是,在分布式和异步的环境下,Processing Time 不能提供确定性,因为它容易受到事件到达系统的速度(例如从消息队列)、事件在系统内操作流动的速度以及中断的影响。
Event Time
Event Time 是事件发生的时间,一般就是数据本身携带的时间。这个时间通常是在事件到达 Flink 之前就确定的,并且可以从每个事件中获取到事件时间戳。
假设所有数据都已到达, Event Time 操作将按照预期运行,即使在处理无序事件、延迟事件、重新处理历史数据时也会产生正确且一致的结果。
Ingestion Time
Ingestion Time 是事件进入 Flink 的时间。 在源操作处,每个事件将源的当前时间作为时间戳,并且基于时间的操作(如时间窗口)会利用这个时间戳。
Ingestion Time 在概念上位于 Event Time 和 Processing Time 之间。 与 Processing Time 相比,它稍微复杂一些,但结果更可预测。因为 Ingestion Time 使用稳定的时间戳(在源处分配一次),所以对事件的不同窗口操作将引用相同的时间戳。
与 Event Time 相比,Ingestion Time 程序无法处理任何无序事件或延迟数据,但程序不必指定如何生成水印。
时间设置
env.setStreamTimeCharacteristic //设置基本时间特性
watermark
对于窗口,程序员需要设置水印来判断窗口是否过期,即是否结束接受新的事件
2.6 ProcessWindowFunction
class MyprocessFunction extends ProcessWindowFunction[(String, Int), Tuple3[String, Long, Long], Tuple, TimeWindow]
//输入,输出,键值,窗口类型
{
override def process(key: Tuple, context: Context, elements: Iterable[(String, Int)], out: Collector[(String, Long, Long)]): Unit = {
var sum = 0
for (in <- elements) {
sum += in._2
}
val time = context.currentProcessingTime
out.collect((key.toString, sum, time))
}
}